home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 2 / The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO / batch / bat2exec.zip / BAT2EXEC.ASM next >
Assembly Source File  |  1990-07-20  |  114KB  |  3,757 lines

  1.         page    66,132
  2. ;============================================================================
  3. ; BAT2EXEC.COM - a batch file compiler
  4. ;
  5. ; Syntax:
  6. ;    BAT2EXEC filename
  7. ;
  8. ; Revision History:
  9. ;
  10. ;    Version 1.0    Initial Release     PC Magazine Vol 9 Num 14
  11. ;    Version 1.1    Bug Fixes               July 19, 1990
  12. ;
  13. ;============================================================================
  14.  
  15.         code    segment
  16.         assume    cs:code
  17.  
  18.         org    2ch
  19. env_segment    dw    ?            ;Word containing the segment
  20.                         ;  of the program's env. block.
  21.         org    80h
  22. command_tail    db    ?            ;Offset of the command tail.
  23.  
  24.         org    100h
  25.  
  26. main:        jmp    initialize
  27. program     db    13,10,"BAT2EXEC 1.1 "
  28. copyright    db    "(c) 1990 Ziff Communications Co.",10,13
  29. author        db    "PC Magazine ",254," Douglas Boling"
  30.         db    10,13,"$",1Ah
  31. ;----------------------------------------------------------------------------
  32. ;Equates used to find data offsets in the compiled program.
  33. ;----------------------------------------------------------------------------
  34. run_buff_size    dw    256            ;Size of runtime buffers
  35.  
  36. std_data_size    equ    offset data_end - data_start
  37. code_start_ptr    equ    [bp + offset code_start - offset data_start]
  38. com_stack_ptr    equ    [bp + offset stack_ptr - offset data_start]
  39. com_prog_size    equ    [bp + offset prog_segsize - offset data_start]
  40. com_label_start equ    [bp + offset label_list_strt - offset data_start]
  41. string1_buff    equ    [bp + offset str1_buff_ptr - offset data_start]
  42. string2_buff    equ    [bp + offset str2_buff_ptr - offset data_start]
  43. string3_buff    equ    [bp + offset str3_buff_ptr - offset data_start]
  44. forloop_ptr    equ    [bp + offset floop_ptr - offset data_start]
  45. stdout_hdl    equ    [bp + offset file_handle1 - offset data_start]
  46. outfile_hdl    equ    [bp + offset file_handle2 - offset data_start]
  47. stdin_hdl    equ    [bp + offset file_handle3 - offset data_start]
  48. infile_hdl    equ    [bp + offset file_handle4 - offset data_start]
  49. environment_seg equ    [bp + offset master_env - offset data_start]
  50. dos_version    equ    [bp + offset version_num - offset data_start]
  51. process_rc    equ    [bp + offset proc_rc - offset data_start]
  52. shift_count    equ    [bp + offset shift_cnt - offset data_start]
  53.  
  54. code_call_size    equ    offset code_call_end - offset code_call
  55. code_jmp_size    equ    offset code_jmp_end - offset code_jmp
  56. code_jc_size    equ    offset code_jc_end - offset code_jc
  57. code_jnc_size    equ    offset code_jnc_end - offset code_jnc
  58. code_jmpdis_size   equ       offset code_jmpdis_end - offset code_jmpdis
  59. code_leasi_size equ    offset code_leasi_end - offset code_leasi
  60. code_movsi_size equ    offset code_movsi_end - offset code_movsi
  61. code_movsiim_size equ    offset code_movsiim_end - offset code_movsiim
  62. code_leadi_size equ    offset code_leadi_end - offset code_leadi
  63. code_movdi_size equ    offset code_movdi_end - offset code_movdi
  64. code_movdiim_size equ    offset code_movdiim_end - offset code_movdiim
  65. ;============================================================================
  66. ;Compiler data
  67. ;============================================================================
  68. fileecho    db    0            ;File echo flag
  69. lineecho    db    0            ;Current line echo flag
  70.  
  71. command_table    db    "IF",0                  ;Commands processed by
  72.         db    "REM",0                 ;  compiler
  73.         db    "FOR",0
  74.         db    "ECHO",0
  75.         db    "GOTO",0
  76.         db    "EXIT",0
  77.         db    "PAUSE",0
  78.         db    "SHIFT",0
  79.         db    "SET",0
  80.         db    "CALL",0
  81.         db    "PATH",0
  82.         db    "PROMPT",0
  83.         db    "CD",0                  ;DOS commands internal to
  84.         db    "MD",0                  ;  command.com.
  85.         db    "RD",0
  86.         db    "CLS",0
  87.         db    "DIR",0
  88.         db    "DEL",0
  89.         db    "REN",0
  90.         db    "VER",0
  91.         db    "VOL",0
  92.         db    "CTTY",0
  93.         db    "CHCP",0
  94.         db    "TYPE",0
  95.         db    "COPY",0
  96.         db    "DATE",0
  97.         db    "TIME",0
  98.         db    "ERASE",0
  99.         db    "CHDIR",0
  100.         db    "MKDIR",0
  101.         db    "RMDIR",0
  102.         db    "BREAK",0
  103.         db    "RENAME",0
  104.         db    "DELETE",0
  105.         db    "VERIFY",0
  106.         db    "COMMAND",0,0
  107.  
  108. batcmd_jmptbl    dw    if_cmd            ;if command
  109.         dw    rem_cmd         ;rem command
  110.         dw    for_cmd         ;for command
  111.         dw    echo_cmd        ;echo command
  112.         dw    goto_cmd        ;goto command
  113.         dw    rem_cmd         ;exit command
  114.         dw    pause_cmd        ;pause command
  115.         dw    shift_cmd        ;shift command
  116.         dw    set_cmd         ;set command
  117.  
  118.         dw    internal_cmd        ;call command
  119.         dw    path_cmd         ;Path command
  120.         dw    prompt_cmd         ;Prompt command
  121.         dw    internal_cmd        ;DOS internal command
  122.         dw    external_cmd        ;DOS program
  123.         dw    label_cmd        ;Process BAT label
  124. batcmd_jmptbl1    =    $
  125.  
  126. ifstr1        db    "ERRORLEVEL"
  127. ifstr2        db    "EXIST"
  128.  
  129. internal_cmdsw    db    "/C "                   ;Switch for transient commands
  130.  
  131. for_active_flag db    0            ;Set if parsing a FOR loop
  132. goto_active    db    0            ;Set if goto parsed
  133. goto_data_ptr    dw    0            ;Data offset of last goto    
  134.  
  135. cmd_switches    db    ?            ;Used if command line switches
  136. cmd_switch_end    =    $            ;  needed.
  137.  
  138. last_routine    dw    offset init_code_next    ;Last canned routine used.
  139.  
  140. codebuff_start    dw    0            ;Buffer to construct the code
  141. codebuff_ptr    dd    0            ;  image of the COM file.
  142.  
  143. databuff_start    dw    ?            ;Buffer to hold the data
  144. databuff_end    dw    ?            ;  image of the COM file.
  145.  
  146. firstlabel    dw    -1            ;Ptr to 1st label in COM file
  147.  
  148. outbuff_ptr    dd    0            ;Buffer to hold the final
  149. outbuff_end    dw    0            ;  image of the COM file.
  150.  
  151. quote_flag    db    0            ;Disable translate flag
  152. redirect_in    db    0            ;Input redirection flag
  153. redirect_out    db    0            ;Output redirection flag
  154.  
  155. pipe_toggle    db    0            ;Piping file flag
  156. pipein_file    dw    0
  157. pipein_flag    db    0
  158. pipeout_file    dw    0
  159. pipeout_flag    db    0
  160. pipe1_file    dw    0
  161.         db    "T^M^P_$1.!!!",0    ;Name of piping file 1
  162. pipe2_file    dw    0
  163.         db    "T^M^P_$2.!!!",0    ;Name of piping file 2
  164.  
  165. inbuff_ptr    dw    offset end_of_code+512    ;Buffer for BAT file
  166. inbuff_size    dw    16384            ;Size of input buffer
  167.  
  168. file_pointer    dw    ?            ;Ptr to BAT data not read.
  169. file_handle    dw    ?            ;Handle of BAT file
  170. file_linecount    dw    0            ;Line number being processed.
  171.  
  172. com_string    db    ".COM",0        ;Extension for output file
  173. outfile_name    db    13 dup (" ")        ;Name of output file.
  174.  
  175. filemsg1    db    13,10,"Error in line $" ;File identification message.
  176.  
  177. errmsg0     db    "Need DOS 2.0 or greater$"
  178. errmsg1     db    13,10,"Syntax: BAT2EXEC filename.ext",13,10,"$"
  179. errmsg2     db    "Can",39,"t find input file$"
  180. errmsg3     db    "Not enough memory$"
  181. errmsg4     db    "No input file specified$"
  182. errmsg5     db    "COM file size too big$"
  183. errmsg6     db    "Syntax error$"
  184. errmsg7     db    "Compiler data buffer full$"
  185. errmsg8     db    "Label defined more than once$"
  186. errmsg9     db    "Label "
  187. errmsg9labl    db    8 dup (" ")
  188.         db    "not found$"
  189. errmsg10    db    "Illegal disk specified$"
  190. errmsg11    db    "FOR loops cannot be nested$"
  191.  
  192. endmsg        db    13,10,"$"
  193.  
  194. ;----------------------------------------------------------------------------
  195. ; Start of compiler code.
  196. ;----------------------------------------------------------------------------
  197. initialize    proc    near
  198.         assume    cs:code,ds:code,es:code
  199.         mov    dx,offset program    ;Display copyright message.
  200.         mov    ah,9
  201.         int    21h
  202.         cld                ;Set string operations 'up.'
  203.         mov    ah,30h            ;Get DOS version, run only
  204.         int    21h            ;  if 2.0 or greater.
  205.         xchg    al,ah            ;Swap major, minor numbers
  206.         mov    dx,offset errmsg0    ;Bad DOS version
  207.         cmp    ah,2
  208.         jb    jmp_disp_error
  209.  
  210.         mov    sp,offset end_of_code + 512    ;Move stack
  211.         mov    ah,4ah                ;Reduce memory
  212.         mov    bx,1000h            ; allocation to 64K
  213.         int    21h
  214.  
  215.         mov    ax,inbuff_ptr        ;Compute start of buffer for
  216.         add    ax,inbuff_size        ;  COM file data.
  217.         mov    databuff_start,ax
  218.  
  219.         mov    ah,48h            ;Allocate memory block for
  220.         mov    bx,1000h        ;  intermediate buffer.
  221.         int    21h
  222.         mov    dx,offset errmsg3    ;Not enough memory msg
  223.         jc    jmp_disp_error
  224.         mov    word ptr codebuff_ptr[2],ax    ;Save segment.
  225.  
  226.         mov    ah,48h            ;Allocate memory block for
  227.         mov    bx,1000h        ;  output file buffer.
  228.         int    21h
  229.         jc    jmp_disp_error
  230.         mov    word ptr outbuff_ptr[2],ax    ;Save segment.
  231. ;
  232. ;Parse the command line for switches.
  233. ;
  234.         mov    si,offset command_tail
  235.         xor    cx,cx
  236.         or    cl,[si]         ;Get command line length
  237.         je     init_0                  ;If zero, report no filename
  238.         inc    si
  239. parse_cmdline_l1:
  240.         xor    bl,bl            ;Search for the next
  241.         call    scanline        ;  non-space character.
  242.         jnc    init_1                  ;If zero, report no filename
  243. init_0:
  244.         mov    dx,offset errmsg1
  245.         jmp    short jmp_disp_error    ;If none, report no filename
  246. init_1:
  247.         mov    al,[si]
  248.         cmp    al,"/"                  ;See if command switch
  249.         je    parse_error
  250.         call    loadbatfile        ;Load input BAT file
  251.         jc    jmp_disp_error
  252.         jmp    short parse_cmdline_end
  253. parse_error:
  254.         mov    dx,offset errmsg2
  255. jmp_disp_error:
  256.         jmp    disp_error
  257. parse_cmdline_end:
  258. ;
  259. ;Compile BAT file line by line.
  260. ;
  261.         mov    si,inbuff_ptr        ;SI points to input BAT file
  262.         mov    di,databuff_start    ;DI points to COM file data.
  263.         add    di,std_data_size
  264. new_line:
  265.         inc    file_linecount        ;Inc line number
  266.         mov    al,fileecho        ;Copy the file echo status to
  267.         mov    lineecho,al        ;  the line echo flag
  268.         xor    bl,bl            ;Look for 1st character
  269.         call    scan4char
  270.         jnc    comp_1
  271.         cmp    al,13            ;See if carrage return, if so
  272.         je    new_line        ;  continue, else assume end
  273.         jmp    short comp_end        ;  of file.
  274. comp_1:
  275.         call    redirect_check
  276.         cmp    byte ptr [si],'@'    ;See if non echo prefix
  277.         jne    comp_2
  278.         mov    lineecho,0        ;Don't echo this line
  279.         inc    si            ;Move past @
  280. comp_2:
  281.         call    parse            ;Parse 1st word in the line.
  282.         jc    comp_error
  283.         jmp    new_line
  284. comp_error:
  285.         jmp    disp_error
  286. comp_end:
  287. ;
  288. ;Inline code complete, append terminate code.
  289. ;
  290.         call    redirect_close
  291.         mov    databuff_end,di     ;Save ptr to end of data.
  292.         les    di,codebuff_ptr
  293.         assume    es:nothing
  294.         mov    si,offset end_code    ;Append terminate code
  295.         mov    cx,offset end_code_end-offset end_code
  296.         rep    movsb
  297.         mov    word ptr codebuff_ptr,di ;Save ptr to end of COM code.
  298. ;
  299. ;File processed. Assemble data and code into one routine.  Start by
  300. ;stringing the canned routines together using the links set by the
  301. ;INCLUDE routine.
  302. ;
  303.         les    di,outbuff_ptr         ;Get ptr to output buffer
  304.         mov    si,offset init_code_next ;  for COM file.
  305. file_1:     mov    cx,[si-2]        ;Get size of routine
  306.         push    [si]            ;Save pointer to next routine
  307.         add    si,4            ;Skip past number of links
  308.         rep    movsb            ;Copy routine to COM file.
  309.         pop    si
  310.         or    si,si            ;See if last routine
  311.         jne    file_1            ;No, loop back.
  312. ;
  313. ;Save starting offset of data to be used by the COM program.
  314. ;
  315.         mov    bp,offset data_start_ptr-offset init_code
  316.         mov    ax,100h         ;AX = end pointer
  317.         add    ax,di            ;Add length of canned routines.
  318.         mov    es:[bp],ax        ;Save data start pointer
  319.         mov    bp,di            ;Use BP as starting data offset
  320.  
  321.         mov    si,databuff_start    ;Compute length of COM data
  322.         mov    cx,databuff_end     ;  plus the canned routines.
  323.         sub    cx,si
  324.         add    ax,cx            ;Add data length to end ptr
  325. ;
  326. ;Now that we have the length of the canned routines and the data, we can
  327. ;compute the starting offset of the inline code.  Use this number to adjust
  328. ;the jump table entries in the label list.  While fixing offsets check to
  329. ;see that all labels have code offsets, if not, print no label error msg.
  330. ;When complete, append data to file.
  331. ;
  332.         mov    bx,offset firstlabel    ;Get pointer to the first label
  333.         mov    dx,[bx]         ;Get offset to 1st label entry
  334.         add    dx,bx            ;Add in BX to get absolute off
  335. file_11:
  336.         cmp    word ptr [bx],-1    ;See if at end of label list.
  337.         je    file_13
  338.         add    bx,[bx]         ;Get next in list
  339.         cmp    word ptr [bx+2],-1    ;See if label ptr to code
  340.         je    file_12         ;  initialized. No, error.
  341.         add    [bx+2],ax        ;Add starting offset of code
  342.         jmp    short file_11
  343. file_12:
  344.         mov    si,bx            ;Label not defined as a
  345.         add    si,5            ;  destination.  Print error
  346.         xor    cx,cx            ;  message inc lost label.
  347.         mov    cl,[bx+4]        ;Get size of label
  348.         push    cs
  349.         pop    es
  350.         mov    di,offset errmsg9labl
  351.         rep    movsb
  352.         mov    dx,offset errmsg9    ;Label not found msg
  353.         jmp    disp_error
  354. file_13:
  355.         rep    movsb            ;Append data to COM file.
  356.         sub    dx,databuff_start    ;Set pointer to 1st label list
  357.         mov    es:com_label_start,dx    ;Initialize pointer.
  358. ;
  359. ;Append the inline code to the program.
  360. ;
  361.         mov    ax,100h
  362.         add    ax,di
  363.         mov    es:code_start_ptr,ax    ;Save offset of main code.
  364.  
  365.         mov    cx,word ptr codebuff_ptr
  366.         mov    si,codebuff_start    ;Get pointer to code
  367.         mov    ds,word ptr codebuff_ptr[2]
  368.         assume    ds:nothing
  369.         sub    cx,si            ;Get size of code
  370.         add    ax,cx            ;Make sure canned routines
  371.         jnc    file_2            ;  and data < 64 K bytes.
  372. file_too_big:    mov    dx,offset errmsg5    ;COM file too big msg
  373.         jmp    disp_error
  374. file_2:
  375.         rep    movsb            ;Append inline code.
  376. ;
  377. ;Compute the size of the data buffers and the stack used by the COM program.
  378. ;Write these numbers to the COM file data area.
  379. ;
  380.         push    cs
  381.         pop    ds
  382.         assume    ds:code
  383.         add    ax,512            ;Add room for stack
  384.         jc    file_too_big
  385.         and    ax,0fffeh        ;Set stack on even word.
  386.         mov    es:com_stack_ptr,ax    ;Save run time stack pointer
  387.         add    ax,2            ;Make room for buff length word
  388.         mov    es:string1_buff,ax    ;Save ptr to parsing buffer.
  389.         add    ax,258            ;Add room for buffer 2
  390.         jc    file_too_big
  391.         mov    es:string2_buff,ax    ;Save ptr to parsing buffer 2
  392.         add    ax,258            ;Add room for buffer
  393.         jc    file_too_big
  394.         mov    es:string3_buff,ax    ;Save ptr to For loop buffer
  395.         add    ax,256            ;Add room for buffer
  396.         jc    file_too_big
  397.  
  398.         mov    outbuff_end,di        ;Save end pointer to file
  399.         add    ax,15
  400.         jc    file_3            ;Compute size of COM file
  401.         mov    cl,4            ;  in paragraphs.
  402.         shr    ax,cl
  403.         mov    es:com_prog_size,ax    ;Save file size
  404.         mov    byte ptr es:shift_count,0    ;Clear shift count
  405. file_3:
  406. ;
  407. ;Write file to disk.
  408. ;
  409.         mov    ah,3ch            ;Create file
  410.         xor    cx,cx            ;Normal attributes
  411.         mov    dx,offset outfile_name    ;Name of file
  412.         int    21h
  413.  
  414.         mov    bx,ax            ;Copy handle
  415.         mov    ah,40h            ;Write file
  416.         push    ds
  417.         lds    dx,outbuff_ptr        ;Get start of buffer
  418.         mov    cx,cs:[outbuff_end]    ;Get number of bytes to write
  419.         sub    cx,dx
  420.         int    21h            ;Write file to disk
  421.         pop    ds
  422.  
  423.         mov    ah,3eh            ;Close file
  424.         int    21h
  425. ;
  426. ;Compile complete. Clean up and end.
  427. ;
  428. good_exit:
  429.         xor    al,al            ;Return code = 0
  430. exit:
  431.         push    ax            ;Save return code
  432.         mov    ah,49h            ;Release memory block used
  433.         mov    es,word ptr cs:[codebuff_ptr+2] ;  for file buffer.
  434.         int    21h
  435.  
  436.         pop    ax            ;Get back return code
  437.         mov    ah,4Ch            ;Terminate
  438.         int    21h
  439. ;
  440. ;Display error message.
  441. ;
  442. disp_error:
  443.         push    cs
  444.         pop    ds
  445.         assume    ds:code
  446.         cmp    file_linecount,0
  447.         je    disp_error1        ;If processing a file, print
  448.         push    dx            ;  a message informing the
  449.         mov    dx,offset filemsg1    ;  user the line that
  450.         call    printmsg        ;  contained the error.
  451.         mov    ax,file_linecount
  452.         call    hex2asc
  453.         mov    dx,offset endmsg
  454.         call    printmsg
  455.         pop    dx
  456. disp_error1:
  457.         call    printmsgcr        ;print string
  458.         mov    al,01            ;Terminate with RC = 1
  459.         jmp    short exit
  460.  
  461. ;-----------------------------------------------------------------------------
  462. ; PARSE  Parse a statment.
  463. ; Entry:  SI - Pointer to string to parse.
  464. ;      DI - Pointer to end of COM file data.
  465. ; Exit:   CF - Set if error.
  466. ;      SI - Updated.
  467. ;-----------------------------------------------------------------------------
  468. parse        proc    near
  469.         mov    bx,14
  470.         mov    al,[si]         ;See if label
  471.         cmp    al,":"
  472.         je    parse_2
  473.  
  474.         mov    bx,12
  475.         cmp    al,"%"                  ;See if cmd line param or env
  476.         je    parse_2         ;  var. If so, internal cmd
  477.  
  478.         mov    ax,[si+1]        ;See if change to default disk
  479.         cmp    al,":"
  480.         jne    parse_1
  481.         mov    bx, 12            ;Set internal command.
  482.         cmp    ah," "
  483.         jbe    parse_2
  484. parse_1:
  485.         call    capsword        ;Capitalize batch command
  486.         push    di            ;Search list of BAT cmds.
  487.         mov    di,offset command_table
  488.         call    findstr
  489.         pop    di
  490. parse_2:
  491.         push    bx            ;Scan past command except for
  492.         cmp    bx,8            ;  external progs, inter cmds,
  493.         ja    parse_3         ;  and labels.
  494.         mov    bl,1
  495.         call    scan4char
  496.         jnc    parse_3         ;If end of line, back up to
  497.         dec    si            ;  show CR.
  498. parse_3:
  499.         pop    bx
  500.         shl    bx,1            ;Compute offset of routine to
  501.         add    bx,offset batcmd_jmptbl ;  call.
  502.         call    [bx]            ;Call routine to compile line.
  503.         ret
  504. parse        endp
  505.  
  506. ;-----------------------------------------------------------------------------
  507. ; FINDSTR  determines if a string is in a list.
  508. ; Entry:  SI - Pointer to ASCII string to find.
  509. ;      DI - Pointer to list of ASCIIZ strings.
  510. ;      CX - Size of string
  511. ; Exit:   CF - Clear if string found
  512. ;      BX - If CF clear, index into list
  513. ;-----------------------------------------------------------------------------
  514. findstr     proc    near
  515.         push    cx
  516.         push    es
  517.         push    cs            ;Point ES:DI to table of
  518.         pop    es            ;  batch commands.
  519.         mov    dx,cx            ;Save length of string
  520.         xor    bx,bx            ;Zero index counter
  521. finds_1:
  522.         push    si
  523.         mov    cx,dx            ;Restore command size
  524.         repe    cmpsb            ;Compare command
  525.         pop    si
  526.         je    string_found
  527.         inc    bx
  528.         xor    al,al
  529.         cmp    [di-1],al
  530.         jne    finds_2
  531.         dec    di
  532. finds_2:
  533.         mov    cx,10            ;Scan to next zero
  534.         repne    scasb
  535.         cmp    byte ptr [di],0     ;See if second zero. If so
  536.         jne    finds_1         ;  end of list.
  537.         mov    bx,13
  538.         stc                ;Indicate string not found
  539. findstr_exit:
  540.         pop    es
  541.         pop    cx
  542.         ret
  543. string_found:
  544.         cmp    bx,12            ;If past the BAT commands,
  545.         jb    findstr_3        ;  then it is an internal cmd.
  546.         mov    bx,12
  547. findstr_3:
  548.         clc                ;Set string found flag
  549.         jmp    short findstr_exit
  550. findstr     endp
  551.  
  552. ;-----------------------------------------------------------------------------
  553. ; CAPSWORD capitalizes word pointed to by SI
  554. ; Entry:  SI - Pointer to ASCII word to capitalize
  555. ; Exit:   CX - Size of word
  556. ;-----------------------------------------------------------------------------
  557. capsword    proc near
  558.         assume    ds:nothing,es:nothing
  559.         push    ax
  560.         push    di
  561.         push    si
  562.         push    es
  563.         push    ds            ;Set ES:DI = DS:SI
  564.         pop    es
  565.         mov    di,si
  566.         xor    cx,cx            ;Clear byte counter.
  567. caps_1:
  568.         lodsb                ;Get character
  569.         cmp    al," "                  ;Allow any non-space character
  570.         jbe    caps_exit
  571.         cmp    al,"a"                  ;If between a and z,
  572.         jb    caps_2           ;  capitalize it, else, exit
  573.         cmp    al,"z"
  574.         ja    caps_exit
  575.         and    al,0DFh
  576. caps_2:
  577.         stosb                ;Save character
  578.         inc    cx            ;Inc byte counter
  579.         jmp    short caps_1
  580. caps_exit:
  581.         pop    es
  582.         pop    si
  583.         pop    di
  584.         pop    ax
  585.         ret
  586. capsword    endp
  587.  
  588. ;-----------------------------------------------------------------------------
  589. ; REDIRECT CLOSE post process redirection commands
  590. ; Entry:  DI - Pointer to end of COM file data.
  591. ; Exit:   CF - Set if error.
  592. ;      Batch file line updated to remove any redirection symbols
  593. ;-----------------------------------------------------------------------------
  594. redirect_close    proc    near
  595.         assume    cs:code,ds:code
  596.         cmp    redirect_in,0        ;See if redirecton active
  597.         je    redirclose_1
  598.         mov    redirect_in,0
  599.         mov    bx,offset redirci_next    ;Append close redirect file
  600.         call    include_code        ;  routine to code.
  601.         xor    cx,cx
  602.         call    inline_code
  603. redirclose_1:
  604.         cmp    redirect_out,0        ;See if redirecton active
  605.         je    redirclose_2
  606.         mov    redirect_out,0
  607.         mov    bx,offset redirco_next    ;Append close redirect file
  608.         call    include_code        ;  routine to code.
  609.         xor    cx,cx
  610.         call    inline_code
  611. redirclose_2:
  612.         cmp    pipein_flag,0        ;See if in pipe curr active
  613.         je     redirclose_3
  614.         mov    dx,pipein_file        ;Get offset of input pipe file
  615.         mov    cx,1            ;Indicate parameter type
  616.         mov    bx,offset redirdel_next    ;Delete the piping file
  617.         call    include_code
  618.         call    inline_code        
  619.         mov    pipein_flag,0        ;Clear flag
  620. redirclose_3:
  621.         cmp    pipeout_flag,0        ;See if out pipe curr active
  622.         je     redirclose_exit
  623.         mov    dx,pipeout_file        ;Get offset of input pipe file
  624.         xor    bx,bx            ;Add output redirection code
  625.         xor    ax,ax            ;  to file.
  626.         call    redirect_openi
  627.         mov    pipein_flag,1        ;Set pipe input flag
  628.         mov    pipeout_flag,0        ;Clear pipe output flag
  629.         mov    pipein_file,dx        ;Copy pointer to filename
  630. redirclose_exit:
  631.         ret
  632. redirect_close    endp
  633.  
  634. ;-----------------------------------------------------------------------------
  635. ; REDIRECT CHECK process redirection commands
  636. ; Entry:  SI - Pointer to current BAT file line
  637. ;      DI - Pointer to end of COM file data.
  638. ; Exit:   CF - Set if error.
  639. ;      Batch file line updated to remove any redirection symbols
  640. ;-----------------------------------------------------------------------------
  641. redirect_check    proc    near
  642.         assume    cs:code,ds:code
  643.         push    si
  644.         call    redirect_close
  645.         mov    quote_flag,0
  646. redirect_1:
  647.         mov    bp,si            ;Save current position
  648.         lodsb
  649.         cmp    al,'"'                  ;See if quote
  650.         jne    redirect_2
  651.         not    quote_flag
  652. redirect_2:
  653.         cmp    quote_flag,0        ;Ignore characters in quotes
  654.         jne    redirect_1
  655. ;
  656. ; Check for piping
  657. ;
  658.         cmp    al,'|'                  ;Check for piping symbol
  659.         jne    redirect_5 
  660.         mov    byte ptr [si-1],13    ;Replace | with CR
  661.  
  662.         mov    bx,offset pipe1_file    ;Get offset of pipe file to
  663.         cmp    pipe_toggle,0        ;  use.  Alternate files so
  664.         jne    redirect_3         ;  that input and output files
  665.         mov    bx,offset pipe2_file    ;  don't get mixed up.
  666. redirect_3:
  667.         not    pipe_toggle
  668.         xor    dx,dx            ;If file not already used, 
  669.         or     dx,[bx]            ;  load the filename into 
  670.         jne    redirect_4         ;  the COM data buffer.
  671.         mov    dx,di
  672.         sub    dx,databuff_start    ;Compute offset of filename
  673.         mov    [bx],dx            ;Save pointer to filename
  674.         lea    si,[bx+2]        ;Get address of filename
  675.         mov    ah,1    
  676.         call    copy_string        ;Copy name to COM data buffer
  677.         xor    al,al            ;Terminate filename with zero
  678.         stosb
  679. redirect_4:
  680.         mov    pipeout_file,dx
  681.         mov    pipeout_flag,1
  682.         xor    bx,bx            ;Add output redirection code
  683.         xor    ax,ax            ;  to file.
  684.         call    redirect_openo
  685.         jmp    short redirect_exit    ;Terminate line scan.
  686. ;
  687. ; Check for output redirection
  688. ;
  689. redirect_5:
  690.         cmp    al,'>'                  ;Check for redirect out
  691.         jne    redirect_7
  692.         xor    bx,bx
  693.         cmp    byte ptr [si],'>'       ;Check for append redirect
  694.         jne    redirect_6
  695.         lodsb                ;Remove 2nd >
  696.         inc    bx
  697. redirect_6:
  698.         push    bx            ;Save append flag
  699.         xor    bl,bl
  700.         call    scan4char        ;Get filename
  701.         mov    dx,di
  702.         mov    ah,1            ;Copy only one word
  703.         call    copy_string
  704.         xor    al,al            ;Terminate name with zero
  705.         stosb
  706.         sub    dx,databuff_start    ;Compute offset of filename
  707.         pop    ax
  708.         call    redirect_openo
  709.         call    erase_redirect        ;Erase redirect from line.
  710.         jmp    short redirect_1
  711. redirect_7:
  712.         cmp    al,'<'                  ;Check for redirect in
  713.         jne    redirect_10
  714.         xor    bl,bl
  715.         call    scan4char        ;Get filename
  716.         mov    dx,di
  717.         mov    ah,1            ;Copy only one word
  718.         call    copy_string
  719.         xor    al,al            ;Terminate name with zero
  720.         stosb
  721.         sub    dx,databuff_start    ;Compute offset of filename
  722.         call    redirect_openi
  723.         call    erase_redirect        ;Erase redirect from line.
  724.         jmp    redirect_1
  725. redirect_10:
  726.         cmp    al,13
  727.         je    redirect_exit
  728.         jmp    redirect_1
  729. redirect_exit:
  730.         clc
  731.         pop    si
  732.         ret
  733. redirect_check    endp
  734.  
  735. ;-----------------------------------------------------------------------------
  736. ; REDIRECT OPENO process redirection commands
  737. ; Entry:  AX - 1 = append file.
  738. ; Entry:  DX - Offset from data buffer start of file name
  739. ;      BX - 0 no translation of filename.
  740. ;-----------------------------------------------------------------------------
  741. redirect_openo    proc    near
  742.         assume    cs:code,ds:code
  743.         push    si
  744.         push    ax            ;Save append flag
  745.         mov    cx,0031h        ;Indicate parameter type
  746.         or    bx,bx            ;See if env var or cmd line
  747.         je    redirect_oo1        ;  parms.
  748.  
  749.         mov    bx,offset procstr_next    ;Get offset of translate
  750.         call    include_code        ;  routine. Include if needed.
  751.  
  752.         mov    bx,offset str1_buff_ptr - offset data_start
  753.         mov    cx,0032h        ;Indicate parameter type
  754.         call    inline_code        ;Insert translate code.
  755. redirect_oo1:
  756.         mov    bx,offset rediroo_next    ;Append open redirect file
  757.         call    include_code
  758.         pop    bx            ;Restore append flag
  759.         call    inline_code
  760.         mov    redirect_out,1        ;Set redirect active flag
  761.         pop    si
  762.         ret
  763. redirect_openo    endp
  764.  
  765. ;-----------------------------------------------------------------------------
  766. ; REDIRECT OPENI loads code to open a file for input redirection
  767. ; Entry:  DX - Offset from data buffer start of file name
  768. ;      BX - 0 no translation of filename.
  769. ;-----------------------------------------------------------------------------
  770. redirect_openi    proc    near
  771.         assume    cs:code,ds:code
  772.         push    si
  773.         mov    cx,1            ;Indicate parameter type
  774.         or    bx,bx            ;See if env var or cmd line
  775.         je    redirect_oi1        ;  parms.
  776.  
  777.         mov    bx,offset procstr_next    ;Get offset of translate
  778.         call    include_code        ;  routine. Include if needed.
  779.  
  780.         mov    bx,offset str1_buff_ptr - offset data_start
  781.         mov    cx,2            ;Indicate parameter type
  782.         call    inline_code        ;Insert translate code.
  783. redirect_oi1:
  784.         mov    bx,offset rediroi_next    ;Append open redirect file
  785.         call    include_code
  786.         call    inline_code
  787.         mov    redirect_in,1        ;Set redirect active flag
  788.         pop    si
  789.         ret
  790. redirect_openi    endp
  791.  
  792. ;-----------------------------------------------------------------------------
  793. ; ERASE REDIRECT
  794. ; Entry:  BP - Pointer to redirect character
  795. ;      SI - Pointer to end of redirect phrase.
  796. ;-----------------------------------------------------------------------------
  797. erase_redirect    proc    near
  798.         assume    cs:code,ds:code
  799.         push    di            ;Save ptr to data buffer
  800.         mov    al,' '
  801.         mov    di,bp            ;Get start of redirect string
  802.         dec    si
  803. erase_1:
  804.         stosb
  805.         cmp    di,si
  806.         jb    erase_1
  807.         pop    di
  808.         ret
  809. erase_redirect    endp
  810.  
  811. ;-----------------------------------------------------------------------------
  812. ; IF CMD compiles an IF command.
  813. ; Entry:  SI - Pointer to character after the IF command
  814. ;      DI - Pointer to end of compiled data.
  815. ; Exit:   AL - Error code if CF set
  816. ;      CF - Set if error
  817. ;      SI,DI updated.
  818. ;-----------------------------------------------------------------------------
  819. if_cmd        proc    near
  820.         assume    cs:code,ds:code
  821.         xor    bl,bl            ;Find 1st char of next word
  822.         call    scan4char
  823.         mov    cx,si            ;Save pointer to test
  824.         mov    dx,di
  825.         mov    bp,0            ;Clear 'NOT' flag
  826. ;
  827. ;See if NOT prefix is used in test
  828. ;
  829.         lodsw                ;Get 1st two chars of test
  830.         or    ax,2020h
  831.         cmp    ax,'on'                 ;See if 'no'
  832.         jne    if_cmd_chk_cmp
  833.         lodsw                ;Get 2nd and 3rd characters
  834.         or    al,20h            ;Convert 3rd char to lower
  835.         cmp    al,'t'                  ;  case.   See if last char is
  836.         jne    if_cmd_chk_cmp         ;  't' followed by s space
  837.         cmp    ah,' '
  838.         ja    if_cmd_chk_cmp 
  839.         inc    bp
  840.         xor    bl,bl            ;Find next word
  841.         call    scan4char
  842.         mov    cx,si
  843. ;
  844. ;Test for string compare by looking for == signs.
  845. ;
  846. if_cmd_chk_cmp:
  847.         mov    si,cx            ;Restore pointer to condition
  848.         mov    bl,3            ;Find next space or equal sign
  849.         call    scan4char
  850.         jc    if_syntax_jmp
  851.         xor    bl,bl
  852.         call    scan4char        ;Find next word
  853.         cmp    word ptr [si],"=="    ;See if string compare        
  854.         je     if_cmd_cmp1        ;No, check other tests
  855.         jmp    if_cmd_chk_errlev
  856. if_cmd_cmp1:
  857.         inc    si            ;Move SI past equals signs
  858.         inc    si
  859.         xor    bl,bl            ;Find second string
  860.         call    scan4char
  861.         jnc    if_cmd_cmp2
  862. if_syntax_jmp:
  863.         jmp    if_syntax
  864. if_cmd_cmp2:
  865.         push    si            ;Save pointer to 2nd string
  866.         mov    si,cx            ;Restore ptr to 1st string
  867.         push    di            ;Save ptr to size byte
  868.         inc    di
  869.         mov    dx,di            ;Save ptr to start of string
  870.         sub    dx,databuff_start
  871.         mov    ah,1            ;Copy only one word
  872.         call    copy_string        ;Load string into data space
  873.         xor    al,al
  874.         stosb
  875.         or    bx,bx            ;See if translation is needed
  876.         pop    bx            ;Restore pointer to size byte
  877.         mov    [bx],cl         ;Save length of string
  878.         mov    cl,1            ;Assume LEA parameter call
  879.         je    if_cmd_03
  880.  
  881.         mov    bx,offset procstr_next    ;Append translate string
  882.         call    include_code        ;  routine to code.
  883.         mov    bx,offset str2_buff_ptr - offset data_start
  884.         mov    cx,0021h        ;Indicate parameter type
  885.         call    inline_code        ;Insert translate code.
  886.         mov    dx,bx            ;Copy ptr to buffer.
  887.         mov    cx,2            ;Use MOV parameter type
  888. if_cmd_03:
  889.         pop    si            ;Restore ptr to 2nd string
  890.         push    dx            ;Save pointer to 1st string
  891.         push    cx            ;Save parameter type
  892. if_cmd_04:
  893.         push    di            ;Save ptr to size byte
  894.         inc    di
  895.         mov    dx,di            ;Save ptr to start of string
  896.         sub    dx,databuff_start
  897.         mov    ah,1
  898.         call    copy_string        ;Load string into data space
  899.         xor    al,al
  900.         stosb
  901.         or    bx,bx            ;See if translation is needed
  902.         pop    bx
  903.         mov    [bx],cl         ;Save length of string
  904.         mov    cx,10h            ;Set parameter type
  905.         je    if_cmd_06
  906.  
  907.         mov    bx,offset procstr_next    ;Append translate string
  908.         call    include_code        ;  routine to code.
  909.         mov    bx,offset str1_buff_ptr - offset data_start
  910.         mov    cx,0021h        ;Indicate parameter type
  911.         call    inline_code        ;Insert translate code.
  912.         mov    dx,bx            ;Copy ptr to buffer.
  913.         mov    cx,20h            ;Use proper parameter type
  914. if_cmd_06:
  915.         mov    bx,offset ifequal_next    ;Append comparison code
  916.         call    include_code
  917.         pop    bx            ;Restore param 1 type
  918.         and    bl,0fh
  919.         or    cl,bl            ;Combine parameter types
  920.         mov    bx,dx            ;Move parameter 2
  921.         pop    dx            ;Restore parameter 1
  922.         call    inline_code        ;Add call to string compare
  923.         jmp    if_cmd_10
  924. if_syntax:
  925.         mov    dx,offset errmsg6    ;Syntax error.
  926.         stc
  927.         jmp    if_exit
  928. ;
  929. ;See if ERRORLEVEL test.
  930. ;
  931. if_cmd_chk_errlev:
  932.         mov    si,cx            ;Restore pointer to 1st string
  933.         mov     bx,cx            ;Save pointer to 1st string
  934.         mov    di,offset ifstr1    ;See if ERRORLEVEL test
  935.         call    capsword
  936.         cmp    cx,10
  937.         jne    if_cmd_2
  938.         repe    cmpsb            ;Compare strings
  939.         jne    if_cmd_2
  940.         mov    bx,offset iferrlev_next ;Save offset of errlev code
  941.         push    bx            ;  on stack.  Use exist code
  942.         jmp    short if_cmd_21     ;  to append error code.
  943. ;
  944. ;See if EXIST test.
  945. ;
  946. if_cmd_2:
  947.         mov    si,bx            ;Restore pointer to 1st string
  948.         mov    di,offset ifstr2    ;See if EXIST test
  949.         cmp    cx,5            ;Check length of string
  950.         jne    if_syntax
  951.         repe    cmpsb            ;Compare strings
  952.         jne    if_syntax
  953.         mov    bx,offset ifexist_next    ;Save test existance code off
  954.         push    bx
  955. if_cmd_21:
  956.         xor    bl,bl
  957.         call    scan4char        ;Scan to next word.
  958.         mov    di,dx            ;Restore data pointer
  959.         sub    dx,databuff_start
  960.         mov    ah,1
  961.         call    copy_string
  962.         xor    al,al            ;Terminate string with zero.
  963.         stosb
  964.         mov    cl,21h            ;Set parameter type
  965.         or    bx,bx            ;See if translation is needed
  966.         je    if_cmd_3
  967.  
  968.         mov    bx,offset procstr_next    ;Append translate string
  969.         call    include_code        ;  routine to code.
  970.         mov    bx,offset str1_buff_ptr - offset data_start
  971.         mov    cx,0021h        ;Indicate parameter type
  972.         call    inline_code        ;Insert translate code.
  973.         mov    dx,bx            ;Copy ptr to buffer.
  974.         mov    cl,22h            ;Use proper parameter type
  975. if_cmd_3:
  976.         pop    bx            ;Restore test code offset
  977.         call    include_code
  978.         mov    bx,offset str2_buff_ptr - offset data_start
  979.         call    inline_code        ;Insert exist test call
  980. if_cmd_10:
  981.         mov    cx,200h         ;Include Jump if carry opcode
  982.         or    bp,bp
  983.         je    if_cmd_12
  984.         mov    cx,300h         ;Change to Jump if not carry
  985. if_cmd_12:
  986.         call    inline_code
  987.         push    ax            ;Save address of jmp to modify
  988.         push    word ptr codebuff_ptr    ;Save current code buff ptr
  989. ;
  990. ;Compile the remainder of the line as if it were a normal statment.
  991. ;
  992.         xor    bl,bl            ;Scan for next word
  993.         call    scan4char
  994.         call    parse            ;Compile remainder of line.
  995.  
  996.         pop    cx            ;Compute the difference for the
  997.         pop    bx            ;  jmp opcode.
  998.         jc    if_exit         ;If error during parse, exit.
  999.         push    es
  1000.         mov    ax,word ptr codebuff_ptr
  1001.         mov    es,word ptr codebuff_ptr[2]
  1002.         sub    ax,cx
  1003.         mov    es:[bx],ax        ;Save jmp offset
  1004.         pop    es
  1005.         clc
  1006. if_exit:
  1007.         ret
  1008. if_cmd        endp
  1009.  
  1010. ;-----------------------------------------------------------------------------
  1011. ; FOR CMD compiles an FOR command.
  1012. ; Entry:  SI - Pointer to character after the FOR command
  1013. ;      DI - Pointer to end of compiled data.
  1014. ; Exit:   AL - Error code if CF set
  1015. ;      CF - Set if error
  1016. ;      SI,DI updated.
  1017. ;-----------------------------------------------------------------------------
  1018. for_cmd     proc    near
  1019.         assume    cs:code,ds:code    
  1020.         cmp    for_active_flag,0        
  1021.         je    for_cmd_0
  1022.         mov    dx,offset errmsg11    ;No nested FOR loops
  1023.         stc
  1024.         jmp    for_exit
  1025. for_cmd_0:
  1026.         mov    goto_active,0        ;Clear goto detect flag
  1027.         inc    for_active_flag
  1028.         xor    bl,bl            ;Find 1st char of next word
  1029.         call    scan4char
  1030.         jc    jmp_for_syntax
  1031.         mov    bp,si            ;Save pointer to loop variable
  1032.         mov    dx,di
  1033.         sub    dx,word ptr databuff_start
  1034. ;
  1035. ;Copy the set data to the com file data area.  As always, if environment
  1036. ;variables or command line parameters are in the data, insert a call to
  1037. ;the translate routine before calling the for loop routine.
  1038. ;
  1039. for_cmd_1:
  1040.         lodsb                ;Scan until '(' is found
  1041.         cmp    al,13            ;  indicating the start of the
  1042.         jne    for_cmd_2        ;  data set.
  1043. jmp_for_syntax:
  1044.         jmp    for_syntax
  1045. for_cmd_2:
  1046.         cmp    al,'('
  1047.         jne    for_cmd_1
  1048.         mov    ah,2            ;Copy until ')' found.
  1049.         call    copy_string
  1050.         xor    al,al            ;Terminate string with zero.
  1051.         stosb
  1052.  
  1053.         push    word ptr codebuff_ptr    ;Save current code buff ptr
  1054.         mov    cl,11h            ;Set parameter type
  1055. ;        or    bx,bx            ;See if translation is needed
  1056. ;        je    for_cmd_3
  1057.  
  1058.         mov    bx,offset procstr_next    ;Append translate string
  1059.         call    include_code        ;  routine to code.
  1060.         mov    bx,offset str3_buff_ptr - offset data_start
  1061.         mov    cx,0021h        ;Indicate parameter type
  1062.         call    inline_code        ;Insert translate code.
  1063.         mov    dx,bx            ;Copy ptr to buffer.
  1064.         mov    cl,12h            ;Use proper parameter type
  1065. for_cmd_3:
  1066.         mov    bx,offset forloop_next
  1067.         call    include_code
  1068.         mov    bx,di            ;Initialize for loop data
  1069.         sub    bx,databuff_start    ;  structure.
  1070.         mov    word ptr [di],0
  1071.         inc    di
  1072.         inc    di
  1073.         call    inline_code        ;Insert call to loop code.
  1074.         mov    cx,200h         ;Include Jump if carry opcode
  1075.         call    inline_code
  1076.         push    ax            ;Save address of jmp to modify
  1077.         push    word ptr codebuff_ptr    ;Save current code buff ptr
  1078.  
  1079. ;
  1080. ;Scan the remainder of the line. Replace all instances of the loop variable
  1081. ;with a special code that the run time translate routine understands.
  1082. ;
  1083.         xor    bl,bl            ;Find DO
  1084.         call    scan4char
  1085.         jc    for_syntax_1
  1086.         mov    bl,1            ;Find end of 'DO'
  1087.         call    scan4char
  1088.         jc    for_syntax_1
  1089.         xor    bl,bl            ;Find start of loop command.
  1090.         call    scan4char
  1091.         jc    for_syntax_1
  1092.         push    si            ;Save pointer to command.
  1093.         push    di            ;Save data buffer pointer.
  1094.         mov    di,si
  1095.         mov    bl,2            ;Find the end of the line.
  1096.         call    scan4char
  1097.         mov    dx,si            ;Save pointer to end of line
  1098. for_cmd_4:
  1099.         mov    si,bp            ;Get ptr to loop variable.
  1100.         mov    cx,3            ;Scan the remainder of the
  1101.         repe    cmpsb            ;  line for the loop variable.
  1102.         jne    for_cmd_5        ;  When found, replace with
  1103.         dec    di            ;  % followed by 7fh. This
  1104.         dec    di            ;  flag tells the runtime
  1105.         mov    ax,207fh        ;  xlate routine to sub in
  1106.         stosw                ;  the loop string.
  1107. for_cmd_5:
  1108.         cmp    di,dx            ;See if at the end of the line.
  1109.         jb    for_cmd_4
  1110.         pop    di            ;Restore data buffer ptr
  1111.         pop    si            ;Restore ptr to command.
  1112. ;
  1113. ;Compile the remainder of the line as if it were a normal statment.
  1114. ;
  1115.         call    parse            ;Compile remainder of line.
  1116.  
  1117.         pop    dx            ;Get code ptr after loop code
  1118.         pop    bx            ;Get addr of JC
  1119.         pop    ax            ;Get code ptr to loop code
  1120.         jc    for_exit1
  1121.  
  1122.         sub    ax,word ptr codebuff_ptr ;Compute displacment from END
  1123.         sub    ax,3             ;  of JMP opcode.
  1124.         mov    cx,400h         ;Insert JMP opcode after code
  1125.         call    inline_code        ;  for statments inside FOR
  1126.         mov    ax,word ptr codebuff_ptr;  loop.
  1127.         sub    ax,dx
  1128.         push    es
  1129.         mov    es,word ptr codebuff_ptr[2]
  1130.         mov    es:[bx],ax
  1131.         pop    es
  1132. ;
  1133. ; If goto parsed during FOR, place jump for goto after FOR loop
  1134. ;
  1135.         cmp    goto_active,0
  1136.         je     for_exit
  1137.         mov    dx,goto_data_ptr
  1138.         mov    bx,offset gotodly_next    ;Append goto delay 
  1139.         call    include_code        ;  routine to code.
  1140.         mov    cx,1
  1141.         call    inline_code        ;Add code to COM file.
  1142. for_exit:
  1143.         clc
  1144. for_exit1:
  1145.         mov    for_active_flag,0    ;Clear flag
  1146.         ret
  1147. for_syntax_1:
  1148.         add    sp,6            ;Clean off stack
  1149. for_syntax:
  1150.         mov    dx,offset errmsg6    ;Syntax error
  1151.         stc
  1152.         jmp    short for_exit1
  1153. for_cmd     endp
  1154.  
  1155. ;-----------------------------------------------------------------------------
  1156. ; GOTO CMD compiles a goto command.
  1157. ; Entry:  SI - Pointer to first character after the command.
  1158. ;      DI - Pointer to end of compiled data.
  1159. ; Exit:   AL - Error code if CF set
  1160. ;      CF - Set if error
  1161. ;      SI,DI updated.
  1162. ;-----------------------------------------------------------------------------
  1163. goto_cmd    proc    near
  1164.         assume    cs:code,ds:code
  1165.         mov    goto_active,1        ;Needed for FOR loop
  1166.         mov    bp,di            ;Save ptr to start of string.
  1167.         xor    bl,bl            ;Find the first nonspace char.
  1168.         call    scan4char
  1169.         push    si
  1170.         xor    ax,ax
  1171.         stosw                ;Save word in case FOR loop
  1172.         xor    ah,ah            ;  delay goto.
  1173.         call    copy_string        ;Copy label to COM data.
  1174.         xor    al,al            ;Terminate label with zero
  1175.         stosb
  1176.         pop    si
  1177.         mov    dx,offset errmsg8    ;Check to see if label found.
  1178.         or    cx,cx            ;If not, error.
  1179.         je    goto_cmd_error
  1180.         cmp    for_active_flag,0    ;If in for loop, force eval
  1181.         jne    goto_c1            ;  Jmp must occur after FOR
  1182.  
  1183.         or    bx,bx            ;See if env var or cmd line
  1184.         je    goto_c2         ;  parms.  If not hard code jmp
  1185. goto_c1:
  1186.         mov    bx,offset procstr_next    ;Get offset of translate
  1187.         call    include_code        ;  routine. Include if needed.
  1188.  
  1189.         mov    dx,bp            ;Get pointer to label.
  1190.         sub    dx,databuff_start    ;Compute offset.
  1191.         mov    goto_data_ptr,dx    ;Save offset in case FOR loop
  1192.         add    dx,2            ;Move past word ptr
  1193.         mov    bx,offset str1_buff_ptr - offset data_start
  1194.         mov    cx,0021h        ;Indicate parameter type
  1195.         call    inline_code        ;Insert translate code.
  1196.         mov    dx,bx
  1197.         mov    cx,32h            ;Use proper parameter type
  1198.         mov    bx,offset goto_next    ;Append goto string
  1199.         call    include_code        ;  routine to code.
  1200.         xor    bx,bx
  1201.         cmp    for_active_flag,0    ;If in FOR loop delay goto.
  1202.         je    goto_c11        ;  Pass ptr to word to save
  1203.         mov    bx,goto_data_ptr    ;  destination address.
  1204. goto_c11:
  1205.         call    inline_code        ;Add code to COM file.
  1206.         jmp    goto_cmd_exit
  1207. ;
  1208. ;Since label doesn't use env vars or cmd line params, hard code JMP.
  1209. ;
  1210. goto_c2:
  1211.         mov    di,bp            ;Reset data ptr to ignore label
  1212.         call    getlabel        ;See if label in list.
  1213.         mov    ax,bx            ;Copy pointer to label pointer
  1214.         add    ax,2            ;  to code.
  1215.         sub    ax,databuff_start    ;Compute offset of pointer
  1216.         mov    cx,100h         ;Insert JMP opcode.
  1217.         call    inline_code
  1218. goto_cmd_exit:
  1219.         mov    bl,2
  1220.         call    scan4char        ;Scan to the end of the line.
  1221.         clc
  1222. goto_cmd_exit1: ret
  1223. goto_cmd_error:
  1224.         stc
  1225.         jmp    short goto_cmd_exit1
  1226. goto_cmd       endp
  1227.  
  1228. ;-----------------------------------------------------------------------------
  1229. ; LABEL CMD processes a label found in the bat file.
  1230. ; Entry:  SI - Pointer to first character of the label
  1231. ;      DI - Pointer to end of compiled data.
  1232. ; Exit:   AL - Error code if CF set
  1233. ;      CF - Set if error
  1234. ;      SI,DI updated.
  1235. ;-----------------------------------------------------------------------------
  1236. label_cmd    proc    near
  1237.         assume    cs:code,ds:code
  1238.         inc    si            ;Move past ':'
  1239.         call    getlabel
  1240.         cmp    word ptr [bx+2],-1    ;See if list entry initialized
  1241.         jne    label_error        ;  if so error.
  1242.         mov    ax,word ptr codebuff_ptr
  1243.         mov    [bx+2],ax        ;Save code ptr in COM data
  1244.         mov    bl,2
  1245.         call    scan4char        ;Scan to the end of the line.
  1246.         clc
  1247. label_exit:
  1248.         ret
  1249. label_error:
  1250.         mov    dx,offset errmsg8    ;Two identical labels
  1251.         stc
  1252.         jmp    short label_exit
  1253. label_cmd    endp
  1254.  
  1255. ;-----------------------------------------------------------------------------
  1256. ; GETLABEL searches the label list in the data area.  If a matching label entry
  1257. ;   is found it is returned, if not a label entry is created.
  1258. ; Entry:  SI - Pointer to first character of the label
  1259. ;      DI - Pointer to end of compiled data.
  1260. ; Exit:   BX - Points to label entry.
  1261. ;      SI,DI updated.
  1262. ;-----------------------------------------------------------------------------
  1263. getlabel    proc    near
  1264.         assume    cs:code,ds:code
  1265.         call    capsword        ;Convert to caps & get length.
  1266.         cmp    cx,8            ;Max length of a label 8
  1267.         jbe    getlabel_1        ;  characters to be consistant
  1268.         mov    cx,8            ;  with DOS.
  1269. getlabel_1:
  1270.         mov    bp,di            ;Save data ptr
  1271.         mov    di,offset firstlabel    ;Get ptr to the 1st label
  1272.         mov    bx,di
  1273.         cmp    word ptr [di],-1    ;See if any labels defined.
  1274.         je    getlabel_2        ;No, skip label list search.
  1275.  
  1276.         push    cx            ;Save label size
  1277.         add    bx,[bx]         ;Point to first label
  1278.         call    lblsrch_code        ;Search label list.
  1279.         pop    cx
  1280.         mov    di,bp            ;Create label entry.
  1281.         jnc    getlabel_exit
  1282. getlabel_2:
  1283.         mov    di,bp            ;Create label entry.
  1284.         mov    ax,-1
  1285.         stosw                ;Clear end of list tag
  1286.         stosw                ;Indicate unitialized label
  1287.         mov    al,cl
  1288.         stosb                ;Save length of label
  1289.         rep    movsb            ;Copy label into data buffer
  1290.         mov    ax,bp
  1291.         sub    ax,bx            ;Compute offset to new label
  1292.         mov    [bx],ax         ;Load offset in prev. label
  1293.         mov    bx,bp            ;Get start of label entry
  1294. getlabel_exit:
  1295.         clc
  1296.         ret
  1297. getlabel    endp
  1298.  
  1299. ;-----------------------------------------------------------------------------
  1300. ; EXTERNAL CMD compiles a routine to exexute a program.
  1301. ; Entry:  SI - Pointer to character after the command
  1302. ;      DI - Pointer to end of compiled data.
  1303. ; Exit:   AL - Error code if CF set
  1304. ;      CF - Set if error
  1305. ;      SI,DI updated.
  1306. ;-----------------------------------------------------------------------------
  1307. external_cmd    proc    near
  1308.         assume    cs:code,ds:code
  1309.         mov    dx,di            ;Save ptr to filename
  1310.         sub    dx,databuff_start    ;Compute offset.
  1311.         mov    ah,1
  1312.         call    copy_string        ;Copy filename to COM data.
  1313.         dec    si            ;Back up one char
  1314.         xor    al,al            ;Terminate filename with zero
  1315.         stosb
  1316.         inc    di
  1317.         push    di            ;Save ptr to command line tail
  1318.         xor    ah,ah
  1319.         call    copy_string        ;Copy command line tail.
  1320.         mov    ax,000dh        ;Append CR and zero
  1321.         stosw
  1322.         pop    bp            ;Save length of cmd line tail.
  1323.         inc    cl            ;  Adjust for the CR since 
  1324.         mov    [bp-1],cl        ;  ProcStr will add CR to the
  1325.         sub    bp,databuff_start    ;  count.  Exec prog fixes 
  1326.         mov    cx,11h            ;  this at run time.
  1327.         or    bx,bx            ;See if translation code needed
  1328.         je    externalcmd_1
  1329.  
  1330.         push    dx
  1331.         mov    dx,bp            ;Get pointer to cmd line tail
  1332.         mov    bx,offset procstr_next    ;Get offset of translate
  1333.         call    include_code        ;  routine.
  1334.         mov    bx,offset str1_buff_ptr - offset data_start
  1335.         mov    cx,0021h        ;Indicate parameter type
  1336.         call    inline_code        ;Insert translate code.
  1337.         mov    cx,21h            ;Use proper parameter type
  1338.         mov    bp,bx
  1339.         pop    dx
  1340. externalcmd_1:
  1341.         mov    bx,offset external_next ;Append prog launch code
  1342.         call    include_code
  1343.         mov    bx,bp            ;Get ptr to filename
  1344.         call    inline_code        ;Add code to COM file.
  1345.         clc
  1346.         ret
  1347. external_cmd    endp
  1348.  
  1349. ;-----------------------------------------------------------------------------
  1350. ; INTERNAL CMD compiles a command internal to command.com
  1351. ; Entry:  SI - Pointer to character after the command
  1352. ;      DI - Pointer to end of compiled data.
  1353. ; Exit:   AL - Error code if CF set
  1354. ;      CF - Set if error
  1355. ;      SI,DI updated.
  1356. ;-----------------------------------------------------------------------------
  1357. internal_cmd    proc    near
  1358.         assume    cs:code,ds:code
  1359.         inc    di            ;Make room for string size.
  1360.         push    di            ;Save ptr to internal command.
  1361.         push    si
  1362.         mov    si,offset internal_cmdsw
  1363.         movsw                ;Copy /C switch to tell
  1364.         movsb                ;  COMMAND.COM to execute and
  1365.         pop    si            ;  terminate.
  1366.         xor    ah,ah
  1367.         call    copy_string        ;Copy internal command
  1368.         mov    ax,000dh        ;Append CR and zero
  1369.         stosw
  1370.         pop    bp
  1371.         add    cl,3            ;Add length of /c switch
  1372.         mov    [bp-1],cl        ;Save length of command line
  1373.  
  1374.         mov    dx,bp            ;Get pointer to internal cmd
  1375.         sub    dx,databuff_start    ;Compute offset.
  1376.         mov    cx,1
  1377.         or    bx,bx            ;See if translation code needed
  1378.         je    internalcmd_1
  1379.  
  1380.         mov    bx,offset procstr_next    ;Get offset of translate
  1381.         call    include_code        ;  routine.
  1382.         mov    bx,offset str1_buff_ptr - offset data_start
  1383.         mov    cx,0021h        ;Indicate parameter type
  1384.         call    inline_code        ;Insert translate code.
  1385.         mov    cx,2            ;Use proper parameter type
  1386.         mov    dx,bx            ;Get input from str1 buffer
  1387. internalcmd_1:
  1388.         mov    bx,offset intcmd_next    ;Append internal cmd routine
  1389.         call    include_code        ;  to code.
  1390.         call    inline_code        ;Add code to COM file.
  1391.         clc
  1392.         ret
  1393. internal_cmd    endp
  1394.  
  1395. ;-----------------------------------------------------------------------------
  1396. ; PATH CMD compiles a path command
  1397. ; Entry:  Same as SET command
  1398. ;-----------------------------------------------------------------------------
  1399. path_cmd     proc    near
  1400.         assume    cs:code,ds:code
  1401.         mov    bp,2
  1402.         jmp    short set_entry
  1403. path_cmd     endp
  1404.  
  1405. ;-----------------------------------------------------------------------------
  1406. ; PROMPT CMD compiles a path command
  1407. ; Entry:  Same as SET command
  1408. ;-----------------------------------------------------------------------------
  1409. prompt_cmd     proc    near
  1410.         assume    cs:code,ds:code
  1411.         mov    bp,1
  1412.         jmp    short set_entry
  1413. prompt_cmd     endp
  1414.  
  1415. ;-----------------------------------------------------------------------------
  1416. ; SET CMD compiles a command to change variables in the environment
  1417. ; Entry:  SI - Pointer to character after the command
  1418. ;      DI - Pointer to end of compiled data.
  1419. ; Exit:   CF - Set if error
  1420. ;      DX - Offset to error message if CF set.
  1421. ;      SI,DI updated.
  1422. ;-----------------------------------------------------------------------------
  1423. set_cmd     proc    near
  1424.         assume    cs:code,ds:code
  1425.         mov    bp,0            ;Assume not PATH or PROMPT    
  1426. set_entry:
  1427.         push    bp
  1428.         xor    bl,bl            ;Find the first nonspace char.
  1429.         call    scan4char
  1430.         mov    dx,di            ;Save ptr to set command.
  1431.         xor    ah,ah
  1432.         call    copy_string        ;Copy string to COM data
  1433.         xor    al,al            ;Append zero
  1434.         stosb
  1435.         sub    dx,databuff_start    ;Compute offset of data.
  1436.         mov    cx,31h
  1437.         or    bx,bx            ;See if translation code needed
  1438.         je    setcmd_1
  1439.  
  1440.         mov    bx,offset procstr_next    ;Get offset of translate
  1441.         call    include_code        ;  routine.
  1442.         mov    bx,offset str1_buff_ptr - offset data_start
  1443.         mov    cx,21h            ;Indicate parameter type
  1444.         call    inline_code        ;Insert translate code.
  1445.         mov    cx,32h            ;Use proper parameter type
  1446.         mov    dx,bx            ;Get input from str1 buffer
  1447. setcmd_1:
  1448.         mov    bx,offset setenv_next    ;Append set routine to code.
  1449.         call    include_code
  1450.         pop    bx            ;Get PATH/PROMPT flag
  1451.         call    inline_code        ;Add code to COM file.
  1452.         clc
  1453.         ret
  1454. set_cmd     endp
  1455.  
  1456. ;-----------------------------------------------------------------------------
  1457. ; ECHO CMD compiles an ECHO command.
  1458. ; Entry:  SI - Pointer to character after the ECHO command
  1459. ;      DI - Pointer to end of compiled data.
  1460. ; Exit:   AL - Error code if CF set
  1461. ;      CF - Set if error
  1462. ;      SI,DI updated.
  1463. ;-----------------------------------------------------------------------------
  1464. echo_cmd    proc    near
  1465.         assume    cs:code,ds:code
  1466.         mov    dx,si            ;Save pointer to string start
  1467.         inc    dx            ;Move pointer past 1st space
  1468.         xor    bl,bl            ;Echo can either echo a
  1469.         call    scan4char        ;  string to the keyboard or
  1470.         jc    echo_c0         ;  toggle the echo flag.
  1471.         or    al,20h            ;Check for on or off keyword
  1472.         cmp    al,"o"                  ;  to indicate what type of
  1473.         jne    echo_c0         ;  Echo this is.
  1474.         mov    ax,[si+1]        ;Get next two characters
  1475.         or    al,20h            ;Make lower case
  1476.         mov    bl,1
  1477.         cmp    al,"n"                  ;Check for echo on
  1478.         je    echo_c00
  1479.         or    ah,20h            ;Make lower case
  1480.         cmp    ax,"ff"                 ;Check for echo off
  1481.         jne    echo_c0
  1482.         dec    bl
  1483.         mov    ah,[si+3]        ;Get character past word
  1484. echo_c00:
  1485.         cmp    ah," "                  ;Make sure not just the start
  1486.         ja    echo_c0         ;  of another word.
  1487.         mov    fileecho,bl        ;Save status of echo flag
  1488.         mov    bl,2
  1489.         call    scan4char        ;Find end of line.
  1490.         jmp    short echo_exit
  1491. ;
  1492. ;Echo ASCII line, Include code in COM file to echo string.
  1493. ;
  1494. echo_c0:
  1495.         mov    si,dx            ;Restore data pointer
  1496.         mov    dx,di
  1497.         xor    ah,ah
  1498.         call    copy_string        ;Copy string to COM data.
  1499.         mov    ax,0d0ah        ;Terminate line with CRLF
  1500.         stosw
  1501.         xor    al,al            ;Append zero byte
  1502.         stosb
  1503.         mov    cx,1            ;Append runtime routines.
  1504.         sub    dx,databuff_start
  1505.         or    bx,bx            ;Check translate flag, if set
  1506.         je    echo_c21        ;  append translate code 1st.
  1507.         mov    bx,offset procstr_next    ;Append translate string
  1508.         call    include_code        ;  routine to code.
  1509.         mov    bx,offset str1_buff_ptr - offset data_start
  1510.         mov    cx,0021h        ;Indicate parameter type
  1511.         call    inline_code        ;Insert translate code.
  1512.         mov    dx,bx
  1513.         mov    cx,2            ;Use proper parameter type
  1514. echo_c21:
  1515.         mov    bx,offset echo_msg_next ;Append echo string
  1516.         call    include_code        ;  routine to code.
  1517. echo_c3:
  1518.         call    inline_code        ;Add code to COM file.
  1519. echo_cstatus:
  1520. echo_exit:
  1521.         clc
  1522. echo_cmd_exit:
  1523.         ret
  1524. echo_cmd    endp
  1525.  
  1526. ;-----------------------------------------------------------------------------
  1527. ; PAUSE CMD compiles a PAUSE command.
  1528. ; Entry:  SI - Pointer to character after the PAUSE command
  1529. ;      DI - Pointer to end of compiled data.
  1530. ; Exit:   AL - Error code if CF set
  1531. ;      CF - Set if error
  1532. ;      SI,DI updated.
  1533. ;-----------------------------------------------------------------------------
  1534. pause_cmd    proc    near
  1535.         assume    cs:code,ds:code
  1536. ;Append routine if necessary
  1537.         mov    bx,offset pause_next     ;Append PAUSE routine if
  1538.         call    include_code         ;  necessary.
  1539.  
  1540.         mov    cx,0            ;Add inline code with 0 params
  1541.         call    inline_code        ;  to call pause routine.
  1542.  
  1543.         mov    bl,2            ;Scan to end of line
  1544.         call    scan4char
  1545.         clc
  1546. pause_cmd_exit:
  1547.         ret
  1548. pause_cmd    endp
  1549.  
  1550. ;-----------------------------------------------------------------------------
  1551. ; SHIFT CMD compiles a SHIFT command.
  1552. ; Entry:  SI - Pointer to character after the SHIFT command
  1553. ;      DI - Pointer to end of compiled data.
  1554. ; Exit:   AL - Error code if CF set
  1555. ;      CF - Set if error
  1556. ;      SI,DI updated.
  1557. ;-----------------------------------------------------------------------------
  1558. shift_cmd    proc    near
  1559.         assume    cs:code,ds:code
  1560.         mov    bx,offset shift_next     ;Append shift routine if
  1561.         call    include_code         ;  necessary.
  1562.         mov    cx,0            ;Add inline code with 0 params
  1563.         call    inline_code        ;  to call pause routine.
  1564.         mov    bl,2            ;Scan to end of line
  1565.         call    scan4char
  1566.         clc
  1567.         ret
  1568. shift_cmd    endp
  1569.  
  1570. ;-----------------------------------------------------------------------------
  1571. ; REM CMD  Processes remark lines in batch file.
  1572. ; Entry:  SI - pointer to line in BAT file
  1573. ;-----------------------------------------------------------------------------
  1574. rem_cmd     proc near
  1575.         assume    cs:code,ds:code
  1576.         dec    si            ;Back up to make sure we don't
  1577. rem_c1:     lodsb                ;  miss a carrage return.
  1578.         cmp    al,1ah            ;Loop until end of line or end
  1579.         je    rem_exit        ;  of file.
  1580.         cmp    al,13
  1581.         jne    rem_c1
  1582. rem_exit:
  1583.         clc
  1584.         ret
  1585. rem_cmd     endp
  1586.  
  1587. ;-----------------------------------------------------------------------------
  1588. ; COPY STRING copies a string to the com file data buffer.
  1589. ; Entry:  SI - Pointer to 1st character of the string.
  1590. ;      DI - Pointer to end of compiled data.
  1591. ;      AH - 0 = copy until end of line
  1592. ;           1 = copy only one word
  1593. ;           2 = copy until ')'
  1594. ; Exit:   BX - 0 if no environment variables or command line parameters.
  1595. ;      CX - Size of string.
  1596. ;      SI,DI updated.
  1597. ;-----------------------------------------------------------------------------
  1598. copy_string    proc    near
  1599.         assume    cs:code,ds:code
  1600.         push    dx
  1601.         mov    dx,di            ;Copy pointer to string
  1602.         xor    bx,bx            ;Clear param/env flag
  1603.         xor    cx,cx            ;Clear count
  1604. copystr_1:
  1605.         lodsb                ;Get byte
  1606.         cmp    al,13            ;See if carrage return
  1607.         je    copystr_exit        ;Yes, quit.
  1608.         cmp    al,1ah            ;See if EOF
  1609.         je    copystr_exit
  1610. copystr_2:
  1611.         cmp    ah,2            ;See if set copy
  1612.         jne    copystr_3        ;No, skip next test.
  1613.         cmp    al,')'                  ;See if end of set
  1614.         je    copystr_exit        ;Yes, quit.
  1615. copystr_3:
  1616.         cmp    ah,1            ;See if phrase or word copy
  1617.         jne    copystr_4        ;Phase, skip next test.
  1618.         cmp    al,' '                  ;See if end of word.
  1619.         jbe    copystr_exit        ;Yes, quit.
  1620.         cmp    al,'='                  ;Equal sign indicates end of
  1621.         je    copystr_exit        ;  word.
  1622. copystr_4:
  1623.         inc    cx
  1624.         cmp    al,'%'                  ;See if translation needed.
  1625.         jne    copystr_6
  1626.         inc    bh
  1627.         or    bl,bl            ;See if already set.
  1628.         mov    bl,0            ;Clear flag
  1629.         jne    copystr_6        ;If set, this must be the
  1630.         cmp    byte ptr [si],7fh    ;Check for For loop var. If
  1631.         jne    copystr_5        ;  found, copy it removing
  1632.         stosb                ;  the extra space.
  1633.         lodsb
  1634.         inc    si
  1635.         jmp    short copystr_6
  1636. copystr_5:
  1637.         cmp    byte ptr [si],'9'       ;  trailing % of an env var.
  1638.         jbe    copystr_6
  1639.         call    capsword        ;Env var, capitialize it.
  1640.         inc    bl
  1641. copystr_6:
  1642.         stosb                ;Save byte
  1643.         jmp    short copystr_1     ;Loop back.
  1644. copystr_exit:
  1645.         pop    dx
  1646.         ret
  1647. copy_string    endp
  1648.  
  1649. ;-----------------------------------------------------------------------------
  1650. ; INLINE CODE  Adds the necessary inline code to call a canned
  1651. ;        routine.
  1652. ; Entry:  AX - Offset of canned routine.
  1653. ;      CL - (low nibble) Method to pass parameter one
  1654. ;      CL - (high nibble) Method to pass parameter two
  1655. ;      CH - (low nibble) Call/Jump method
  1656. ;      DX - Parameter one
  1657. ;      BX - Parameter two
  1658. ;-----------------------------------------------------------------------------
  1659. inline_code    proc    near
  1660.         push    bp
  1661.         push    si            ;Save pointer to input buffer.
  1662.         push    di
  1663.         push    es
  1664.         les    di,codebuff_ptr     ;Point ES:DI to buffer
  1665.         mov    bp,cx
  1666.         and    cl,0fh            ;Look only at SI code nibble
  1667.         cmp    cl,1            ;Check for LEA SI
  1668.         jne    inline_1
  1669.         mov    si,offset code_leasi
  1670.         mov    [si+2],dx        ;Load paramter one
  1671.         mov    cx,code_leasi_size
  1672.         rep    movsb            ;Copy routine into COM file.
  1673.         jmp    short inline_10
  1674. inline_1:
  1675.         cmp    cl,2            ;Check for MOV SI
  1676.         jne    inline_2
  1677.         mov    si,offset code_movsi
  1678.         mov    [si+2],dx        ;Load parameter one
  1679.         mov    cx,code_movsi_size
  1680.         rep    movsb            ;Copy routine into COM file.
  1681.         jmp    short inline_10
  1682. inline_2:
  1683.         cmp    cl,3            ;Check for MOV SI Immediate
  1684.         jne    inline_10
  1685.         mov    si,offset code_movsiim
  1686.         mov    [si+1],dx        ;Load parameter one
  1687.         mov    cx,code_movsiim_size
  1688.         rep    movsb            ;Copy routine into COM file.
  1689. inline_10:
  1690.         mov    cx,bp            ;Get back code
  1691.         and    cl,0f0h
  1692.         cmp    cl,10h            ;Check for LEA DI
  1693.         jne    inline_11
  1694.         mov    si,offset code_leadi
  1695.         mov    [si+2],bx        ;Load paramter two
  1696.         mov    cx,code_leadi_size
  1697.         rep    movsb            ;Copy routine into COM file.
  1698.         jmp    short inline_13
  1699. inline_11:
  1700.         cmp    cl,20h            ;Check for MOV DI
  1701.         jne    inline_12
  1702.         mov    si,offset code_movdi
  1703.         mov    [si+2],bx        ;Load parameter two
  1704.         mov    cx,code_movdi_size
  1705.         rep    movsb            ;Copy routine into COM file.
  1706.         jmp    short inline_13
  1707. inline_12:
  1708.         cmp    cl,30h            ;Check for MOV immed DI
  1709.         jne    inline_13
  1710.         mov    si,offset code_movdiim
  1711.         mov    [si+1],bx        ;Load parameter two
  1712.         mov    cx,code_movdiim_size
  1713.         rep    movsb            ;Copy routine into COM file.
  1714. inline_13:
  1715.         mov    cx,bp
  1716.         and    ch,0fh
  1717.         jne    inline_20
  1718.         mov    si,offset code_call    ;Code to call the canned
  1719.         mov    cx,code_call_size    ;  routine.
  1720.         mov    [si+1],ax        ;Insert the destination offset.
  1721.         rep    movsb            ;Copy routine into COM file.
  1722.         jmp    short inline_30
  1723. inline_20:
  1724.         cmp    ch,01            ;Check for jmp
  1725.         jne    inline_21
  1726.         mov    si,offset code_jmp    ;Code to jmp to destination.
  1727.         mov    cx,code_jmp_size
  1728.         mov    [si+2],ax        ;Insert the destination offset.
  1729.         rep    movsb            ;Copy routine into COM file.
  1730.         jmp    short inline_30
  1731. inline_21:
  1732.         cmp    ch,02            ;Check for jc
  1733.         jne    inline_22
  1734.         mov    si,offset code_jc    ;Code to jc to destination.
  1735.         mov    cx,code_jc_size
  1736.         lea    ax,[di+3]        ;Save offset of JMP to mod
  1737.         rep    movsb            ;Copy routine into COM file.
  1738.         jmp    short inline_30
  1739. inline_22:
  1740.         cmp    ch,03            ;Check for jnc
  1741.         jne    inline_23
  1742.         mov    si,offset code_jnc    ;Code to jnc to destination.
  1743.         mov    cx,code_jnc_size
  1744.         lea    ax,[di+3]        ;Save offset of JMP to mod
  1745.         rep    movsb            ;Copy routine into COM file.
  1746.         jmp    short inline_30
  1747. inline_23:
  1748.         cmp    ch,04            ;Check for jmp displacment
  1749.         jne    inline_30
  1750.         mov    si,offset code_jmpdis    ;Code to jmp IP relative.
  1751.         mov    [si+1],ax
  1752.         mov    cx,code_jmpdis_size
  1753.         rep    movsb            ;Copy routine into COM file.
  1754. inline_30:
  1755.         mov    word ptr cs:codebuff_ptr,di
  1756.         pop    es
  1757.         pop    di
  1758.         pop    si
  1759.         pop    bp
  1760.         ret
  1761. inline_code    endp
  1762.  
  1763. ;-----------------------------------------------------------------------------
  1764. ; INCLUDE CODE - Appends the routine to the append list if necessary and
  1765. ;         returns the offset of the routine in the compiled program.
  1766. ; Entry:  BX - Pointer to header of canned routine to append.
  1767. ; Exit:   AX - Offset of canned routine in COM file.
  1768. ;-----------------------------------------------------------------------------
  1769. include_code    proc    near
  1770.         assume    ds:code,es:nothing
  1771.         push    cx
  1772.         push    dx
  1773.         mov    ax,[bx-4]        ;Get COM file offset
  1774.         or    ax,ax            ;If zero, routine has not
  1775.         jne    include_exit        ;  been appended.
  1776.         mov    cx,bx            ;Save pointer to new routine
  1777. ;
  1778. ;Address the prevous 'last' routine header.  Update that header, then use
  1779. ;information in that header to compute the offset of the new routine.
  1780. ;
  1781.         xchg    bx,last_routine
  1782.         mov    [bx],cx         ;Add code to chain.
  1783.         mov    ax,[bx-2]        ;Compute offset of new routine
  1784.         add    ax,[bx-4]        ;  by adding the offset of the
  1785.         sub    ax,[bx+2]        ;  prevous routine to its size.
  1786.         mov    bx,cx
  1787.  
  1788.         mov    cx,[bx+2]        ;Get number of called routines.
  1789.         add    ax,cx
  1790.         mov    [bx-4],ax        ;Set offset of code.
  1791.         jcxz    include_exit
  1792.         shr    cx,1            ;If this routine needs other
  1793.         add    bx,4            ;  routines, include them in
  1794.         push    ax            ;  the COM file.
  1795. include_1:
  1796.         push    cx
  1797.         push    bx
  1798.         mov    bx,[bx]
  1799.         call    include_code
  1800.         pop    bx
  1801.         mov    [bx],ax
  1802.         add    bx,2
  1803.         pop    cx
  1804.         loop    include_1
  1805.         pop    ax
  1806. include_exit:
  1807.         pop    dx
  1808.         pop    cx
  1809.         ret
  1810. include_code    endp
  1811. ;-----------------------------------------------------------------------------
  1812. ; PRINTMSG prints the message pointed to by DX to the screen.
  1813. ; Entry:  DX - pointer to ASCII message terminated by $
  1814. ;-----------------------------------------------------------------------------
  1815. printmsg    proc    near
  1816.         assume    ds:nothing,es:nothing
  1817.         push    ds
  1818.         push    cs
  1819.         pop    ds
  1820.         assume    ds:code
  1821.         mov    ah,9            ;Print message
  1822.         int    21h
  1823.         pop    ds
  1824.         ret
  1825. printmsg    endp
  1826.  
  1827. ;-----------------------------------------------------------------------------
  1828. ; PRINTMSGCR calls PRINTMSG, then appends a carriage return to the message.
  1829. ; Entry:  DX - pointer to ASCII message terminated by $
  1830. ;-----------------------------------------------------------------------------
  1831. printmsgcr    proc    near
  1832.         assume    ds:nothing,es:nothing
  1833.         push    dx
  1834.         call    printmsg
  1835.         mov    dx,offset endmsg
  1836.         call    printmsg
  1837.         pop    dx
  1838.         ret
  1839. printmsgcr    endp
  1840.  
  1841. ;-----------------------------------------------------------------------------
  1842. ; HEX2ASC converts a binary number to ASCII and prints it to the screen.
  1843. ; Entry:  AX - binary number
  1844. ;-----------------------------------------------------------------------------
  1845. hex2asc     proc near
  1846.         assume    ds:nothing,es:nothing
  1847.         push    bx
  1848.         mov    cx,5            ;Allow max of five digits
  1849. hex_loop1:
  1850.         xor    dx,dx            ;Clear high word
  1851.         mov    bx,10            ;Load number base
  1852.         div    bx            ;Divide by base (10)
  1853.         add    dl,30h            ;Convert to ascii
  1854.         push    dx            ;Save digit on stack
  1855.         loop    hex_loop1
  1856.         mov    cx,5            ;Allow max of five digits
  1857.         mov    bl,"0"                  ;Set leading zero indicator
  1858. hex_loop2:
  1859.         pop    dx            ;Get digit off stack
  1860.         or    bl,dl            ;Don't print leading zeros.
  1861.         cmp    bl,"0"                  ;The first non zero will
  1862.         je    hex_1            ;  change bl to non-zero.
  1863.         mov    ah,2            ;DOS character output
  1864.         int    21h
  1865. hex_1:
  1866.         loop    hex_loop2
  1867. hex_exit:
  1868.         pop    bx
  1869.         ret
  1870. hex2asc     endp
  1871.  
  1872. ;-----------------------------------------------------------------------------
  1873. ; LOADBATFILE loads the input BAT file.
  1874. ; Entry:  DS:SI - pointer to the name of the file to open
  1875. ; Exit:      CF - clear if successful
  1876. ;
  1877. ;  Support for BAT files larger than 16 K is not currently implimented.
  1878. '
  1879. ;-----------------------------------------------------------------------------
  1880. loadbatfile    proc    near
  1881.         assume    cs:code,ds:code
  1882.         push    si
  1883.         mov    dx,si            ;Save filename pointer
  1884.         mov    di,offset outfile_name    ;Point DI to buffer to hold
  1885.         mov    cx,8            ;  the output file name.
  1886. loadfile_1:
  1887.         lodsb                ;Copy the name until the 
  1888.         cmp    al,' '            ;  extension is reached.
  1889.         je    loadfile_10        
  1890.         cmp    al,'.'
  1891.         je     loadfile_10
  1892.         stosb
  1893.         loop    loadfile_1
  1894. loadfile_10:    
  1895.         mov    si,offset com_string    ;Append COM extension to 
  1896.         movsb                ;  output file name.
  1897.         movsw
  1898.         movsw
  1899.         mov    file_pointer,0        ;Clear file pointer.
  1900.         mov    si,dx            ;Get back filename pointer
  1901.         mov    bl,1            ;Find end of filename
  1902.         call    scanline
  1903.         dec    si
  1904.         mov    byte ptr [si],0     ;Make filename ASCIIZ.
  1905.         mov    ax,3d00h        ;Open file (Read only)
  1906.         int    21h
  1907.         jc    loadfile_error
  1908.         mov    bx,ax            ;Copy file handle
  1909. ;
  1910. ;Read contents into file buffer.
  1911. ;
  1912.         mov    ah,3fh            ;Read input BAT file into
  1913.         mov    dx,inbuff_ptr        ;  memory above stack space
  1914.         mov    cx,inbuff_size         ;Get size of buffer
  1915.         sub    cx,4
  1916.         int    21h            
  1917.         cmp    ax,cx            ;Check if complete file read.
  1918.         jbe    loadfile_2
  1919.         std                ;If there is more of the file
  1920.         push    di            ;  to read, scan backwards to
  1921.         push    es            ;  the end of the last line.
  1922.         push    cs
  1923.         pop    es
  1924.         mov    cx,ax
  1925.         mov    di,ax
  1926.         mov    al,13            ;Scan for last CR
  1927.         repne    scasb
  1928.         mov    ax,di
  1929.         pop    es
  1930.         pop    di
  1931.         mov    file_pointer,ax
  1932.         mov    file_handle,bx
  1933.         cld                ;Reset string flag
  1934. loadfile_2:
  1935.         mov    si,inbuff_ptr
  1936.         add    si,ax
  1937.         mov    word ptr ds:[si],1A0Dh    ;Append CR and EOF bytes
  1938.         mov    word ptr ds:[si+2],1a1ah
  1939.         mov    cx,ax            ;Save new file size
  1940.         mov    si,dx            ;Reset file pointer.
  1941.         mov    ah,3eh            ;Close file.
  1942.         int    21h
  1943.         mov    cs:[file_linecount],0    ;Reset line counter.
  1944. loadfile_exit:
  1945.         clc
  1946. loadfile_exit1:
  1947.         pop    si
  1948.         ret
  1949. loadfile_error:
  1950.         stc
  1951.         mov    dx,offset errmsg2    ;Bad filename specified.
  1952.         jmp    short loadfile_exit1
  1953. loadbatfile    endp
  1954.  
  1955. ;-----------------------------------------------------------------------------
  1956. ; SCANLINE performs the same function as SCAN4CHAR but keeps track of the
  1957. ; carriage returns.
  1958. ; Entry:  SI - pointer to ASCII string
  1959. ;      BL - 0 = find next char, 1 = find next space
  1960. ; Exit:   AL - first nonspace character
  1961. ;      CF - set if carriage return found
  1962. ;-----------------------------------------------------------------------------
  1963. scanline    proc    near
  1964.         call    scan4char        ;Find the next char.
  1965.         jnc    scanline_exit
  1966.         inc    cs:[file_linecount]    ;Point to next line.
  1967.         stc
  1968. scanline_exit:
  1969.         ret
  1970. scanline    endp
  1971.  
  1972. ;-----------------------------------------------------------------------------
  1973. ; SCAN4CHAR scans a string to find the first character.
  1974. ; Entry:  SI - pointer to ASCII string
  1975. ;      BL - 0 = find next char, 
  1976. ;              1 = find next space, 
  1977. ;              2 = find end of line,
  1978. ;              3 = find next space or =.
  1979. ; Exit:   AL - matching character
  1980. ;      SI - pointer to matching character
  1981. ;      CF - set if carriage return or EOF found
  1982. ;-----------------------------------------------------------------------------
  1983. scan4char    proc near
  1984.         assume    ds:nothing,es:nothing
  1985. scan4loop:
  1986.         lodsb
  1987.         cmp    al,13            ;Check for carriage return.
  1988.         je    scan4_eol
  1989.         cmp    al,1ah            ;Check for end of file char.
  1990.         jne    scan4_1
  1991. scan4_eol:
  1992.         stc
  1993.         jmp    short scan4_exit1
  1994. scan4_1:
  1995.         cmp    bl,3
  1996.         je    scan4_equal
  1997.         cmp    bl,1            ;Check if searching for space,
  1998.         je    scan4_space         ;  character, or end of line.
  1999.         ja    scan4loop
  2000.         cmp    al," "                  ;Check for space or other
  2001.         jbe    scan4loop        ;  'white' characters.
  2002.         jmp    short scan4_exit
  2003. scan4_equal:
  2004.         cmp    al,"="            ;Check for exit
  2005.         je    scan4_exit
  2006. scan4_space:
  2007.         cmp    al," "                  ;Check for characters.
  2008.         ja    scan4loop
  2009. scan4_exit:
  2010.         dec    si            ;Back up before character
  2011.         clc
  2012. scan4_exit1:
  2013.         ret
  2014. scan4char    endp
  2015.  
  2016. ;============================================================================
  2017. ;Routines used by compiled program.
  2018. ;============================================================================
  2019. ;!!--------------------------------------------------------------------------
  2020. ;Code fragments used to call canned routines.
  2021. ;----------------------------------------------------------------------------
  2022. code_call    proc    near
  2023.         mov    ax,1234h        ;Set address to call routine.
  2024.         call    ax            ;Call canned routine.
  2025. code_call_end    =    $
  2026. code_call    endp
  2027.  
  2028. code_jmp    proc    near
  2029.         mov    ax,[bp+1234h]        ;Set address to call routine.
  2030.         jmp    ax            ;Jump to new offset.
  2031. code_jmp_end    =    $
  2032. code_jmp    endp
  2033.  
  2034. code_jc     proc    near
  2035.         jnc    code_jc_end        ;Jump over long jmp
  2036.         jmp    initialize        ;This jmp will be modified
  2037. code_jc_end    =    $
  2038. code_jc     endp
  2039.  
  2040. code_jnc    proc    near
  2041.         jc    code_jnc_end        ;Skip over long jmp
  2042.         jmp    initialize        ;This jmp will be modified
  2043. code_jnc_end    =    $
  2044. code_jnc    endp
  2045.  
  2046. code_jmpdis    proc    near
  2047.         jmp    initialize        ;This jmp will be modified
  2048. code_jmpdis_end =    $
  2049. code_jmpdis    endp
  2050.  
  2051. code_leasi    proc    near
  2052.         lea    si,[bp+1234h]        ;Load address of data
  2053. code_leasi_end    =    $
  2054. code_leasi    endp
  2055.  
  2056. code_movsi    proc    near
  2057.         mov    si,[bp+1234h]        ;Load data
  2058. code_movsi_end    =    $
  2059. code_movsi    endp
  2060.  
  2061. code_movsiim    proc    near
  2062.         mov    si,1234h        ;Load immediate data
  2063. code_movsiim_end  =    $
  2064. code_movsiim    endp
  2065.  
  2066. code_leadi    proc    near
  2067.         lea    di,[bp+1234h]        ;Load address of data
  2068. code_leadi_end    =    $
  2069. code_leadi    endp
  2070.  
  2071. code_movdi    proc    near
  2072.         mov    di,[bp+1234h]        ;Load data
  2073. code_movdi_end    =    $
  2074. code_movdi    endp
  2075.  
  2076. code_movdiim    proc    near
  2077.         mov    di,1234h        ;Load immediate data
  2078. code_movdiim_end  =    $
  2079. code_movdiim    endp
  2080.  
  2081. ;----------------------------------------------------------------------------
  2082. ;Predefined data needed for all compiled programs.
  2083. ;----------------------------------------------------------------------------
  2084. data_start    =    $
  2085. code_start    dw    ?            ;Offset of main code routine
  2086. stack_ptr    dw    ?            ;Offset of end of code + stack
  2087. prog_segsize    dw    ?            ;Size of COM prog in paragraphs
  2088. str1_buff_ptr    dw    ?            ;Buffer for parsing strings
  2089. str2_buff_ptr    dw    ?            ;Buffer for parsing strings
  2090. str3_buff_ptr    dw    ?            ;Buffer for For loop variables
  2091. floop_ptr    dw    ?            ;Pointer to for loop string
  2092. file_handle1    dw    ?            ;Saved handle of std output
  2093. file_handle2    dw    ?            ;Handle of output file
  2094. file_handle3    dw    ?            ;Saved handle of std input
  2095. file_handle4    dw    ?            ;Handle of input file
  2096. label_list_strt dw    ?            ;Offset into data of 1st label.
  2097. master_env    dw    ?            ;Segment of environment blk
  2098. version_num    dw    ?            ;DOS version number
  2099. proc_rc     db    ?            ;Return code of last program.
  2100. shift_cnt    db    ?            ;Count of shift parameter
  2101. data_end    =    $
  2102.  
  2103. ;----------------------------------------------------------------------------
  2104. ;INIT CODE Routine at the start of all compiled programs.
  2105. ;----------------------------------------------------------------------------
  2106. init_code_off    dw    100h            ;Pointer to offset in COM file
  2107. init_code_size    dw    offset init_code_end-offset init_code_start
  2108. init_code_next    dw    0            ;Ptr to next routine to append
  2109. init_code_lnks    dw    0            ;Bytes in the dependancy header ;Number of routines called
  2110. init_code_start =    $
  2111.  
  2112. init_code    proc    near
  2113.         assume    cs:code,ds:code,es:code,ss:code
  2114.         cld
  2115.         mov    bp,ds:[offset data_start_ptr - offset init_code + 100h]
  2116.         mov    bp,[bp]
  2117.         mov    sp,com_stack_ptr    ;Move stack pointer
  2118.         mov    bx,com_prog_size    ;Reduce memory allocation
  2119.         mov    ah,4ah            ;Resize memory block
  2120.         int    21h
  2121.         mov    ax,ds:[2ch]        ;Get program environment seg
  2122.         mov    environment_seg,ax    ;  use unless SET cmd used.
  2123.         mov    bx,code_start_ptr    ;Get starting code offset
  2124.         jmp    bx            ;Jump to start of code.
  2125. data_start_ptr    dw    ?            ;Offset of data area.
  2126. init_code    endp
  2127. init_code_end    =    $
  2128.  
  2129. ;----------------------------------------------------------------------------
  2130. ;END CODE Routine appended at the end of all compiled programs.
  2131. ;----------------------------------------------------------------------------
  2132. end_code_off    dw    0            ;Pointer to offset in COM file
  2133. end_code_size    dw    offset end_code_end-offset end_code_start
  2134. end_code_next    dw    0            ;Ptr to next routine to append
  2135. end_code_lnks    dw    0            ;Bytes in the dependancy header ;Number of routines called
  2136. end_code_start    =    $
  2137.  
  2138. end_code    proc    near
  2139.         assume    cs:code,ds:code
  2140.         mov    ax,4c00h        ;Terminate program
  2141.         int    21h
  2142. end_code    endp
  2143. end_code_end    =    $
  2144.  
  2145. ;----------------------------------------------------------------------------
  2146. ;ECHO MSG CODE Routine used print a string to the standard output device
  2147. ; Entry:  DS:SI - offset of string to print.
  2148. ;----------------------------------------------------------------------------
  2149. echo_msg_off    dw    0            ;Pointer to offset in COM file
  2150. echo_msg_size    dw    offset echo_msg_end-offset echo_msg_start
  2151. echo_msg_next    dw    0            ;Ptr to next routine to append
  2152. echo_msg_lnks    dw    0            ;Bytes in the dependancy header ;Number of routines called
  2153. echo_msg_start    =    $
  2154.  
  2155. echo_msg_code    proc    near
  2156.         assume    cs:code,ds:code
  2157.         mov    dl,[si]         ;Get character
  2158.         inc    si
  2159.         or    dl,dl
  2160.         je    echo_msg_1
  2161.         mov    ah,2            ;Print character
  2162.         int    21h
  2163.         jmp    short echo_msg_code
  2164. echo_msg_1:
  2165.         ret
  2166. echo_msg_code    endp
  2167. echo_msg_end    =    $
  2168.  
  2169. ;----------------------------------------------------------------------------
  2170. ;ECHO STATUS CODE Routine used to report the status of the echo flag.
  2171. ; Entry:  AL - Echo flag.
  2172. ;----------------------------------------------------------------------------
  2173. echo_stat_ptr    dw    0            ;Pointer to offset in COM file
  2174. echo_stat_size    dw    offset echo_stat_end-offset echo_stat_start
  2175. echo_stat_next    dw    0            ;Ptr to next routine to append
  2176. echo_stat_lnks    dw    0            ;Bytes in the dependancy header ;Number of routines called
  2177. echo_stat_start =    $
  2178.  
  2179. echo_stat_code    proc    near
  2180.         assume    cs:code,ds:code
  2181.         call    echo_stat_1        ;Push IP on stack
  2182. echo_msg    db    "ECHO is $"
  2183. echo_on     db    "on",10,13,"$"
  2184. echo_off    db    "off",10,13,"$"
  2185. echo_stat_1:
  2186.         pop    dx            ;Pop offset of echo message
  2187.         push    ax            ;Save status of echo flag
  2188.         mov    ah,9
  2189.         int    21h
  2190.         add    dx,offset echo_on-offset echo_msg ;Point to 'on' msg
  2191.         pop    ax
  2192.         or    al,al            ;Check status of echo flag
  2193.         je    echo_report_1
  2194.         add    dx,offset echo_off-offset echo_on ;Point to 'off' msg
  2195.         add    dx,5            ;Point to off message.
  2196. echo_report_1:
  2197.         mov    ah,9            ;Print last part of echo stat
  2198.         int    21h
  2199.         ret
  2200. echo_stat_code    endp
  2201. echo_stat_end    =    $
  2202.  
  2203. ;----------------------------------------------------------------------------
  2204. ;PAUSE CODE Routine used pause execution of the COM file.
  2205. ;----------------------------------------------------------------------------
  2206. pause_ptr    dw    0            ;Pointer to offset in COM file
  2207. pause_size    dw    offset pause_end-offset pause_start
  2208. pause_next    dw    0            ;Ptr to next routine to append
  2209. pause_lnks    dw    0            ;Bytes in the dependancy header ;Number of routines called
  2210. pause_start    =    $
  2211.  
  2212. pause_code    proc    near
  2213.         assume    cs:code,ds:code
  2214.         call    pause_1     ;Push IP on stack
  2215. pause_msg    db    "Strike any key when ready...",13,10,"$"
  2216. pause_1:
  2217.         pop    dx            ;Pop offset of message
  2218.         mov    ah,9            ;Print message.
  2219.         int    21h
  2220.  
  2221.         mov    ah,7            ;Keyboard unfiltered input
  2222.         int    21h            ;  without echo.
  2223.         ret
  2224. pause_code    endp
  2225. pause_end    =    $
  2226.  
  2227. ;----------------------------------------------------------------------------
  2228. ;SHIFT CODE Routine used shift the input parameters by one.
  2229. ;----------------------------------------------------------------------------
  2230. shift_ptr    dw    0            ;Pointer to offset in COM file
  2231. shift_size    dw    offset shift_end-offset shift_start
  2232. shift_next    dw    0            ;Ptr to next routine to append
  2233. shift_lnks    dw    0            ;Bytes in the dependancy header ;Number of routines called
  2234. shift_start    =    $
  2235.  
  2236. shift_code    proc    near
  2237.         assume    cs:code,ds:code
  2238.         inc    byte ptr shift_count     ;Inc shift count.
  2239.         ret
  2240. shift_code    endp
  2241. shift_end    =    $
  2242.  
  2243. ;-----------------------------------------------------------------------------
  2244. ; SCAN_CHAR scans a string to find the first character.
  2245. ; Entry:  SI - pointer to ASCII string
  2246. ;      DL - 0 = find next char, 1 = find next space
  2247. ;      CX - file length
  2248. ; Exit:   AL - first nonspace character
  2249. ;      CF - set if carriage return found
  2250. ;-----------------------------------------------------------------------------
  2251. scan4_off    dw    0            ;Pointer to offset in COM file
  2252. scan4_size    dw    offset scan4_end - offset scan4_start
  2253. scan4_next    dw    0            ;Ptr to next routine to append
  2254. scan4_lnks    dw    0
  2255. scan4_start    =    $
  2256.  
  2257. scan_char    proc near
  2258.         assume    ds:nothing,es:nothing
  2259. scan_loop:
  2260.         lodsb
  2261.         cmp    al,9            ;See if char is tab
  2262.         je    scan_space        ;If before, end of line
  2263.         cmp    al," "                  ;See if char is space.
  2264.         jb    scan_eol        ;If before, end of line
  2265.         je    scan_space
  2266.         or    dl,dl            ;Not space, if looking
  2267.         jne    scan_loop        ;  for space continue.
  2268.         jmp    short scan_exit
  2269. scan_space:
  2270.         or    dl,dl            ;Space found, see if looking
  2271.         je    scan_loop        ;  for one.
  2272. scan_exit:
  2273.         clc
  2274.         ret
  2275. scan_eol:
  2276.         stc
  2277.         ret
  2278. scan_char    endp
  2279. scan4_end    =    $
  2280.  
  2281. ;-----------------------------------------------------------------------------
  2282. ; GETMEMBER  returns a pointer to the Nth word in a line.
  2283. ; Entry:     SI - pointer to line of words
  2284. ;         DH - number of the word to return
  2285. ; Exit:      SI - pointer to word
  2286. ;         CF - Set if word not in line.
  2287. ;-----------------------------------------------------------------------------
  2288. getmember_scan4 equ    [bx-6]
  2289. getmember_off    dw    0            ;Pointer to offset in COM file
  2290. getmember_size    dw    offset getmember_end - offset getmember_start
  2291. getmember_next    dw    0            ;Ptr to next routine to append
  2292. getmember_lnks    dw    2            ;Bytes in the dependancy header
  2293. getmember_start =    $
  2294.         dw    offset scan4_next    ;Offset of called routine.
  2295.  
  2296. getmember    proc    near
  2297.         assume    cs:code,ds:code,es:code,ss:code
  2298.         push    bx
  2299.         call    getmember_0
  2300. getmember_0:
  2301.         pop    bx
  2302. getmember_1:
  2303.         xor    dl,dl
  2304.         call    getmember_scan4     ;Find next word
  2305.         jc    getmember_notfound
  2306.         dec    dh            ;Dec parameter count
  2307.         jle    getmember_2
  2308.         inc    dl
  2309.         call    getmember_scan4     ;Find next space
  2310.         jc    getmember_exit
  2311.         jmp    short getmember_1    ;If not done, loop back.
  2312. getmember_2:
  2313.         dec    si            ;Backup to 1st char in word.
  2314.         clc
  2315. getmember_exit:
  2316.         pop    bx
  2317.         ret
  2318. getmember_notfound:
  2319.         stc
  2320.         jmp    short getmember_exit
  2321. getmember    endp
  2322. getmember_end    =    $
  2323.  
  2324. ;-----------------------------------------------------------------------------
  2325. ; PROCSTRING processes a string to convert any environment variables or
  2326. ;         command line variables.
  2327. ; Entry:  DS:SI - ASCIIZ string to process
  2328. ;      ES:DI - pointer to output buffer.
  2329. ; Exit:   DS:SI - pointer to beginning of new ASCIIZ string.
  2330. ;     [SI-1] - Length of new string.
  2331. ;-----------------------------------------------------------------------------
  2332. procstr_cmdl    equ    [bx-8]
  2333. procstr_env    equ    [bx-6]
  2334. procstr_off    dw    0            ;Pointer to offset in COM file
  2335. procstr_size    dw    offset procstr_end - offset procstr_start
  2336. procstr_next    dw    0            ;Ptr to next routine to append
  2337. procstr_lnks    dw    4            ;Bytes in the dependancy header
  2338.  
  2339. procstr_start    =    $
  2340.         dw    offset subparm_next    ;Offset of called routines.
  2341.         dw    offset subenv_next
  2342.  
  2343. procstr_code    proc    near
  2344.         assume    cs:code,ds:code,es:code
  2345.         push    bx
  2346.         call    procstr_0
  2347. procstr_0:
  2348.         pop    bx
  2349.         push    di
  2350.         push    si
  2351.         mov    ah,255            ;Set size of buffer
  2352. procstr_1:
  2353.         lodsb                ;Get byte from string
  2354.         or    al,al            ;Check for end of string
  2355.         je    procstr_exit
  2356.         cmp    al,"%"                  ;See if special character
  2357. procstr_jmp:
  2358.         je    procstr_3        ;Yes, process special char.
  2359. procstr_2:
  2360.         stosb                ;Store byte from string
  2361.         dec    ah
  2362.         jne    procstr_1
  2363. procstr_exit:
  2364.         xor    al,al            ;Force zero byte end.
  2365.         stosb
  2366.         pop    si
  2367.         pop    di
  2368.         mov    bl,255
  2369.         sub    bl,ah
  2370.         mov    ds:[di-1],bl        ;Store length of string
  2371.         pop    bx
  2372.         ret
  2373. ;
  2374. ;A percent sign has been found indicating a 'soft' parameter.  Three types of
  2375. ;soft parameters are allowed; command line parameter, environment variable,
  2376. ;and for loop parameter.
  2377. ;
  2378. procstr_3:
  2379.         lodsb                ;Get next character
  2380.         dec    cx
  2381.         cmp    al,"%"                  ;If double %, include one
  2382.         je    procstr_2        ;  in string.
  2383.         cmp    al,7fh            ;See if for loop var
  2384.         jne    procstr_32
  2385.         push    si
  2386.         mov    si,forloop_ptr        ;Get ptr to for loop string
  2387. procstr_30:
  2388.         lodsb
  2389.         cmp    al,0            ;If zero, end of string
  2390.         je    procstr_31
  2391.         stosb
  2392.         dec    ah            ;Dec buffer size counter
  2393.         jne    procstr_30        ;If buffer not full, continue
  2394. procstr_31:
  2395.         pop    si            ;Get back source string pointer
  2396.         jmp    short procstr_4
  2397. procstr_32:
  2398.         mov    dh,al            ;Copy and check to see if
  2399.         sub    dh,"0"                  ;  the next char is a number.
  2400.         jb    procstr_5        ;  If so, assume a line
  2401.         cmp    dh,9            ;  parameter.
  2402.         ja    procstr_5
  2403.         call    procstr_cmdl        ;Call cmd line param routine
  2404. procstr_4:
  2405.         or    ah,ah
  2406.         jne    procstr_1
  2407.         jmp    short procstr_exit    ;If at end of string, done
  2408. procstr_5:
  2409.         dec    si            ;Backup to 1st character
  2410.         inc    cx
  2411.         call    procstr_env
  2412.         jmp    short procstr_4
  2413. procstr_code    endp
  2414. procstr_end    =    $
  2415.  
  2416. ;-----------------------------------------------------------------------------
  2417. ; SUBLINEPARAM substitutes a parameter from the command line.
  2418. ; Entry:  ES:DI - pointer to buffer to copy the line parameter
  2419. ;         DH - binary number of the line parameter
  2420. ;         AH - size of buffer
  2421. ; Exit:   ES:DI - pointer to byte after the parameter in the buffer
  2422. ;         CX - remaining length of the buffer
  2423. ;-----------------------------------------------------------------------------
  2424. subparm_getmem    equ    [bx-6]
  2425. subparm_off    dw    0            ;Pointer to offset in COM file
  2426. subparm_size    dw    offset subparm_end - offset subparm_start
  2427. subparm_next    dw    0            ;Ptr to next routine to append
  2428. subparm_lnks    dw    2            ;Bytes in the dependancy header
  2429. subparm_start    =    $
  2430.         dw    offset getmember_next    ;Offset of called routine.
  2431.  
  2432. sublineparam    proc    near
  2433.         assume    cs:code,ds:code,es:code,ss:code
  2434.         push    bx
  2435.         call    sublineparam_1
  2436.         db    "DOS2X",0        ;Dummy %0 parameter for DOS 2x
  2437. sublineparam_1:
  2438.         pop    bx
  2439.         push    cx
  2440.         push    si
  2441.         push    ds
  2442.         mov    si,80h            ;Get ptr to cmd line
  2443.         xor    cx,cx
  2444.         mov    cl,[si]         ;Get number of chars in buffer.
  2445.         inc    si            ;Point to data
  2446.         add    dh,ds:shift_count    ;Add in shift count.
  2447.         or    dh,dh            ;Check count of param to find.
  2448.         jnz    sublineparam_12
  2449. ;
  2450. ;For parameter 0, attempt to look in the env block for the name of the prog.
  2451. ;
  2452.         push    ax            ;Save buffer size in AH
  2453.         mov    ah,30h            ;Get DOS version 
  2454.         int    21h            ;If DOS 2.x, program nane not
  2455.         cmp    al,2            ;  in the env segment.  Use
  2456.         pop    ax
  2457.         ja    sublineparam_10        ;  dunny name instead.
  2458.         lea    si,[bx]            ;Point to dummy parameter
  2459.         jmp    short sublineparam_2
  2460. sublineparam_10:
  2461.         push    es
  2462.         push    di
  2463.         mov    es,ds:[2ch]        ;Get segment of local env    
  2464.         xor    al,al
  2465.         xor    di,di
  2466.         mov    cx,8000h
  2467. sublineparam_11:
  2468.         repne    scasb            ;Find double zero
  2469.         scasb
  2470.         jne    sublineparam_11
  2471.         scasw                ;Scan to name
  2472.         mov    si,di            ;Copy pointer to name
  2473.         pop    di
  2474.         pop    es
  2475.         mov    ds,ds:[2ch]
  2476.         jmp    short sublineparam_2
  2477. sublineparam_12:
  2478.         call    subparm_getmem        ;Get pointer to proper word.
  2479.         jc    sublineparam_exit
  2480. sublineparam_2:
  2481.         lodsb                ;Get character from parameter
  2482.         cmp    al," "                  ;If space, parameter done
  2483.         jbe    sublineparam_exit
  2484.         stosb
  2485.         dec    ah            ;Dec buffer size counter
  2486.         jnz    sublineparam_2
  2487. sublineparam_exit:
  2488.         pop    ds
  2489.         pop    si
  2490.         pop    cx
  2491.         pop    bx
  2492.         ret
  2493. sublineparam    endp
  2494. subparm_end    =    $
  2495. ;-----------------------------------------------------------------------------
  2496. ; SUBENVVAR substitutes a parameter from the program environment block.
  2497. ; Entry:  DS:SI - pointer to enviroment variable.
  2498. ;      ES:DI - pointer to buffer.
  2499. ;         AH - size of buffer.
  2500. ; Exit:   ES:DI - pointer to byte after the parameter in the buffer
  2501. ;      DS:SI - pointer to the character after the line parameter number
  2502. ;         CX - remaining free bytes in the buffer.
  2503. ;-----------------------------------------------------------------------------
  2504. subenv_srchenv    equ    [bx-6]
  2505. subenv_off    dw    0            ;Pointer to offset in COM file
  2506. subenv_size    dw    offset subenv_end-offset subenv_start
  2507. subenv_next    dw    0            ;Ptr to next routine to append
  2508. subenv_lnks    dw    2            ;Bytes in the dependancy header
  2509. subenv_start    =    $
  2510.         dw    offset searchenv_next    ;Call to search environment blk
  2511.  
  2512. subenvvar    proc    near
  2513.         assume    cs:code,ds:code,es:code,ss:code
  2514.         push    bx
  2515.         call    subenvvar_0
  2516. subenvvar_0:
  2517.         pop    bx
  2518.         push    ds
  2519. ;
  2520. ;Compute the length of the variable name.
  2521. ;
  2522.         mov    cx,255
  2523.         push    di            ;Save pointer to internal buff
  2524.         mov    di,si            ;Compute the length of the
  2525.         mov    dx,cx            ;  environment variable by
  2526.         mov    al,"%"                  ;  searching for the trailing
  2527.         repne    scasb            ;  % sign.
  2528.         sub    dx,cx            ;Compute length of variable.
  2529.         dec    dx            ;Subtract % byte from length.
  2530.         mov    cx,di
  2531.         pop    di
  2532.         push    cx            ;Save ptr to end of var
  2533.         call    subenv_srchenv        ;Search environment block.
  2534.         jc    short subenvvar_exit    ;CF set, variable not found.
  2535. ;
  2536. ;Environment variable found. Substitute into string.
  2537. ;
  2538. subenvvar_1:
  2539.         lodsb                ;Get env var character
  2540.         or    al,al            ;Check for end of string
  2541.         je    subenvvar_exit
  2542.         stosb                ;Save character in string
  2543.         dec    ah            ;Dec buffer size count.
  2544.         jne    subenvvar_1        ;If buffer not full, continue
  2545. subenvvar_exit:
  2546.         pop    si            ;Restore string pointer
  2547.         pop    ds            ;Restore segment register
  2548.         pop    bx
  2549.         ret
  2550. subenvvar    endp
  2551. subenv_end    =    $
  2552.  
  2553. ;-----------------------------------------------------------------------------
  2554. ; SEARCH_ENV scans the environment block for a string.
  2555. ; Entry:  DS:SI - pointer to ASCII string
  2556. ;         DX - length of string
  2557. ; Exit:   DS:SI - points to first character of environment string
  2558. ;         CF - clear if string found
  2559. ;-----------------------------------------------------------------------------
  2560. searchenv_off    dw    0               ;Pointer to offset in COM file
  2561. searchenv_size    dw    offset searchenv_end - offset searchenv_start
  2562. searchenv_next    dw    0               ;Ptr to next routine to append
  2563. searchenv_lnks    dw    0
  2564. searchenv_start =    $
  2565.  
  2566. search_env    proc near
  2567.         assume    ds:nothing,es:nothing
  2568.         push    bx
  2569.         push    cx
  2570.         push    di
  2571.         push    es
  2572.         mov    es,environment_seg    ;Get seg of environment blk
  2573.         xor    di,di            ;Point ES:DI to environment.
  2574.         mov    bx,si            ;Save pointer to var name
  2575. search_env_1:
  2576.         mov    si,bx            ;Get back ptr to var name.
  2577.         mov    cx,dx            ;Compare env var to var in
  2578.         repe    cmpsb            ;  string.
  2579.         je    search_env_2        ;Variable found, exit loop
  2580.         xor    al,al            ;Find next environment var.
  2581.         mov    cx,-1            ;Scan the entire segment.
  2582.         repne    scasb
  2583.         cmp    byte ptr es:[di],0    ;If double zero, end of env
  2584.         jne    search_env_1        ;  block. else, loop back.
  2585. search_env_not_found:
  2586.         mov    si,di            ;Point SI to end of env data
  2587.         push    es
  2588.         pop    ds
  2589.         stc
  2590.         jmp    short search_env_exit
  2591. search_env_2:
  2592. ;
  2593. ;Environment variable found. Point DS:SI to the string.
  2594. ;
  2595.         mov    si,di
  2596.         push    es            ;DS:SI points to env string
  2597.         pop    ds
  2598. search_env_3:
  2599.         lodsb                ;Move environment pointer past
  2600.         cmp    al,"="                  ;  the equals sign.
  2601.         jne    search_env_3
  2602.         cmp    byte ptr [si],0
  2603.         je    search_env_not_found
  2604. search_env_4:
  2605.         lodsb                ;Move pointer to first
  2606.         or    al,al            ;  non-space character.
  2607.         jb    search_env_5
  2608.         cmp    al," "
  2609.         jb    search_env_4
  2610. search_env_5:
  2611.         dec    si
  2612.         clc
  2613. search_env_exit:
  2614.         pop    es
  2615.         pop    di
  2616.         pop    cx
  2617.         pop    bx
  2618.         ret
  2619. search_env    endp
  2620. searchenv_end    =    $
  2621.  
  2622. ;----------------------------------------------------------------------------
  2623. ;EXTERNAL CMD  Routine used to launch programs from the COM file.
  2624. ; Entry   DS:SI - Pointer to the ASCIIZ program name
  2625. ;      ES:DI - Pointer to the ASCIIZ command line tail
  2626. ;----------------------------------------------------------------------------
  2627. extern_intcmd    equ    [bx-14]
  2628. extern_echomsg    equ    [bx-12]
  2629. extern_parspath equ    [bx-10]
  2630. extern_launch    equ    [bx-8]
  2631. extern_ifexits    equ    [bx-6]
  2632. extern_pathcnt    equ    [bx]
  2633. extern_path_var equ    [bx+1]
  2634. extern_file_ext equ    [bx+6]
  2635. extern_filename equ    [bx+15]
  2636. extern_filetail equ    [bx+17]
  2637. extern_lostmsg    equ    [bx+19]
  2638. extern_cmdparm    equ    [bx+46]
  2639. extern_pathflag    equ    [bx+49]
  2640. external_ptr    dw    0            ;Pointer to offset in COM file
  2641. external_size    dw    offset external_end - offset external_start
  2642. external_next    dw    0            ;Ptr to next routine to append
  2643. external_lnks    dw    10            ;Bytes in the dependancy header ;Number of routines called
  2644. external_start    =    $
  2645.         dw    intcmd_next        ;Call to launch COMMAND.COM
  2646.         dw    echo_msg_next        ;Call to display string
  2647.         dw    parsepath_next        ;Call to get part of path
  2648.         dw    launch_next        ;Call execute file
  2649.         dw    ifexist_next        ;Call to find file
  2650.  
  2651. external_code    proc    near
  2652.         assume    cs:code,ds:code
  2653.         push    bx
  2654.         call    external_0
  2655.         db    0            ;Cnt to track path search.
  2656.         db    "PATH="
  2657.         db    "COMEXEBAT"
  2658.         dw    0            ;Pointer to filename
  2659.         dw    0            ;Pointer to command line tail
  2660.         db    "Bad command or file name",13,10,0
  2661.         db    "/C "
  2662.         db    0            ;Flag for path search
  2663. external_0:
  2664.         pop    bx            ;Get pointer to local vars.
  2665.         mov    extern_filename,si    ;Save ptr to file name
  2666.         mov    extern_filetail,di    ;Save ptr to command line tail
  2667.         mov    dx,string2_buff     ;Get pointer to free buffer.
  2668.         add    dx,4            ;Make room for /C if needed.
  2669.         mov    byte ptr extern_pathflag,0
  2670.         mov    byte ptr extern_pathcnt,0
  2671. ;Parse path to generate filename.
  2672. external_1:
  2673.         mov    di,dx            ;Get ptr to start of buffer
  2674.         xor    cx,cx            ;Check to see if we need to
  2675.         or    cl,extern_pathcnt    ;  check the directorys in
  2676.         jne    external_19        ;  the path.
  2677. ;The first time through, parse the name without using the path.
  2678.         push    dx
  2679.         push    si
  2680.         xor    dx,dx            ;Assume default drive
  2681.         cmp    byte ptr [si+1],':'    ;See if drive specified    
  2682.         jne    external_11
  2683.         mov    dl,[si]
  2684.         and    dl,0dfh            ;Set to upper case
  2685.         sub    dl,'@'            ;Convert ASCII to number
  2686.         movsw                ;Copy drive letter
  2687.         add    word ptr extern_filename,2  ;Don't use drive in path
  2688. external_11:
  2689.         cmp    byte ptr [si],'\'    ;See if starting at root.
  2690.         je    external_110
  2691.         mov    al,'\'            ;Start at root dir
  2692.         stosb
  2693.         push    si
  2694.         mov    si,di            ;Get pointer to buffer.
  2695.         mov    ah,47h            ;Get current directory
  2696.         int    21h
  2697.         pop    si
  2698.         xor    al,al
  2699.         mov    cx,64
  2700.         repne    scasb            ;Find end of directory string
  2701.         dec    di
  2702.         cmp    byte ptr [di-1],'\'    ;Unless at root dir, add
  2703.         je     external_110
  2704.         mov    al,'\'
  2705.         stosb
  2706. external_110:
  2707.         xor    ax,ax
  2708. external_12:
  2709.         lodsb                ;Get a byte
  2710.         cmp    ax,2e2eh        ;See if we need to back up
  2711.         jne    external_13        ;  one directory.
  2712.         std
  2713.         mov    al,'\'            ;Scan backwards to erase    
  2714.         mov    cx,18            ;  last directory.
  2715.         repne    scasb
  2716.         repne    scasb
  2717.         cld
  2718.         inc    di
  2719.         jmp    short external_12
  2720. external_13:
  2721.         stosb    
  2722.         mov    ah,al            ;Copy last character.
  2723.         cmp    al,'\'            ;See if name specifies a path
  2724.         jne    external_14
  2725.         inc    byte ptr extern_pathflag
  2726. external_14:
  2727.         cmp    al,0
  2728.         jne    external_12
  2729. external_15:
  2730.         dec    di            ;Since DOS does not let the
  2731.         mov    dx,di            ;  user specify the file ext.
  2732.         std                ;  scan back to make sure one
  2733.         mov    cx,5            ;  is not attached.
  2734.         mov    al,'.'
  2735.         repne   scasb    
  2736.         cld
  2737.         jne    external_16
  2738.         inc    di
  2739.         mov    dx,di
  2740. external_16:
  2741.         mov    di,dx
  2742.         pop    si
  2743.         pop    dx
  2744.         jmp    short external_4
  2745. ;Parse the path string to search remaining directorys.
  2746. external_19:
  2747.         cmp    byte ptr extern_pathflag,0  ;If a complete path was
  2748.         jne    external_badcmd            ;  specified, don't search
  2749.         mov    si,extern_filename        ;  the path.
  2750.         call    extern_parspath
  2751.         jnc    external_2        ;If we have checked all
  2752. external_badcmd:
  2753.         lea    si,extern_lostmsg    ;  directories in the path,
  2754.         call    extern_echomsg        ;  display file not found msg.
  2755.         jmp    short external_exit
  2756.  
  2757. ;Append filename to the end of the path.
  2758. external_2:
  2759.         mov    cx,73            ;Max length of filename
  2760. external_3:
  2761.         lodsb
  2762.         cmp    al,' '                  ;See if end of word
  2763.         jbe    external_4
  2764.         cmp    al,'.'                  ;See if end of filename
  2765.         je    external_4
  2766.         stosb
  2767.         loop    external_3
  2768. external_4:
  2769.         mov    al,'.'                  ;Append '.' to filename
  2770.         stosb
  2771.         lea    si,extern_file_ext    ;Get pointer to extensions
  2772.         mov    cx,3            ;3 extension types COM EXE BAT
  2773. external_5:
  2774.         movsw                ;Append extension to filename
  2775.         movsb
  2776.         xor    al,al            ;Termainate with zero
  2777.         stosb
  2778.         push    dx
  2779.         push    si
  2780.         push    cx
  2781.         mov    si,dx            ;Get ptr to start of name
  2782.         call    extern_ifexits        ;Search for file
  2783.         pop    cx
  2784.         pop    si
  2785.         pop    dx
  2786.         jnc    external_6
  2787.         sub    di,4            ;Backup to file extension
  2788.         loop    external_5
  2789.         inc    byte ptr extern_pathcnt ;Look in the next path str
  2790.         jmp    external_1
  2791. external_6:
  2792.         cmp    cx,1            ;See if BAT extension
  2793.         jne    external_8
  2794.         lea    si,extern_cmdparm    ;Get pointer to /C
  2795.         sub    dx,3
  2796.         mov    di,dx            ;Get ptr to string buffer
  2797.         movsw                ;Copy /C param
  2798.         movsb
  2799.         xor    al,al
  2800.         mov    cx,252
  2801.         repne    scasb            ;Find end of filename
  2802.         mov    byte ptr [di-1],' '     ;Fill in zero with space
  2803.         mov    si,extern_filetail    ;Get ptr to command line tail
  2804.         cmp    [si-1],cl
  2805.         ja    external_7
  2806.         mov    cl,[si-1]        ;Get length of cmd line tail
  2807. external_7:
  2808.         rep    movsb
  2809.         mov    byte ptr [di],13    ;Append CR to cmd line.
  2810.         mov    si,dx            ;Get pointer to BAT filename
  2811.         mov    ax,di            ;Compute length of cmd line.
  2812.         sub    ax,dx
  2813.         mov    [si-1],al
  2814.         call    extern_intcmd        ;Launch COMMAND.COM
  2815.         jmp    short external_exit
  2816. external_8:
  2817.         mov    di,extern_filetail    ;Get ptr to command line tail
  2818.         dec    di            ;Back up to buffer length
  2819.         dec    byte ptr [di]        ;Sub CR from length
  2820.         mov    si,dx            ;Get ptr to start of name
  2821.         call    extern_launch        ;Execute program
  2822. external_exit:
  2823.         pop    bx
  2824.         ret
  2825. external_code    endp
  2826. external_end    =    $
  2827.  
  2828. ;-----------------------------------------------------------------------------
  2829. ; PARSEPATH  Parses the PATH and returns a qualified directory from the path.
  2830. ; Entry:  ES:DI - pointer to destination buffer.
  2831. ;         CX - index into the path variable. (zero based.)
  2832. ; Exit:   ES:DI - pointer to ASCIIZ destination filename.
  2833. ;         CF - Set if past end of the path
  2834. ;-----------------------------------------------------------------------------
  2835. parsepath_srenv equ    [bx-6]
  2836. parsepath_off    dw    0             ;Pointer to offset in COM file
  2837. parsepath_size    dw    offset parsepath_end - offset parsepath_start
  2838. parsepath_next    dw    0             ;Ptr to next routine to append
  2839. parsepath_lnks    dw    2
  2840. parsepath_start =    $
  2841.         dw    offset searchenv_next     ;Call to search env block
  2842.  
  2843. parsepath    proc    near
  2844.         assume    cs:code,ds:code,es:code,ss:code
  2845.         push    bx
  2846.         call    parsepath_1
  2847.         db    "PATH"
  2848. parsepath_1:
  2849.         pop    bx        
  2850.         push    dx
  2851.         push    si
  2852.         push    ds
  2853.         mov    dx,4            ;Length of PATH string
  2854.         mov    si,bx            ;Point SI to PATH string
  2855.         call    getcom_srchenv        ;PATH var ptr return in DS:SI
  2856. parsepath_2:
  2857.         dec    cx            ;Dec path segment count
  2858.         jcxz    parsepath_4
  2859. parsepath_3:
  2860.         lodsb                ;Get character
  2861.         or    al,al            ;See if end of path string
  2862.         je    parsepath_notfound
  2863.         cmp    al,';'                  ;See if end of path segment
  2864.         jne    parsepath_3
  2865.         jmp    short parsepath_2
  2866. parsepath_4:
  2867.         lodsb
  2868.         cmp    al,';'                  ;See if end of path segment
  2869.         je    parsepath_5
  2870.         or    al,al            ;See if end of path
  2871.         je    parsepath_5
  2872.         stosb
  2873.         jmp    short parsepath_4
  2874. parsepath_5:
  2875.         push    cs
  2876.         pop    ds
  2877.         cmp    byte ptr es:[di-1],'\'  ;Append \ if necessary.
  2878.         je    parsepath_6
  2879.         mov    al,'\'
  2880.         stosb
  2881. parsepath_6:
  2882.         clc
  2883. parsepath_exit:
  2884.         pop    ds
  2885.         pop    si
  2886.         pop    dx
  2887.         pop    bx
  2888.         ret
  2889. parsepath_notfound:
  2890.         stc
  2891.         jmp    short parsepath_exit
  2892. parsepath    endp
  2893. parsepath_end      =      $
  2894.  
  2895. ;-----------------------------------------------------------------------------
  2896. ; INTCMD  Launches the shell ,usually COMMAND.COM, to run an internal command.
  2897. ; Entry   DS:SI - pointer to the ASCIIZ internal command to run.
  2898. ;-----------------------------------------------------------------------------
  2899. intcmd_launch    equ    [bx-8]
  2900. intcmd_getcom    equ    [bx-6]
  2901. intcmd_off    dw     0            ;Pointer to offset in COM file
  2902. intcmd_size    dw     offset intcmd_end - offset intcmd_start
  2903. intcmd_next    dw     0            ;Ptr to next routine to append
  2904. intcmd_lnks    dw     4
  2905. intcmd_start    =      $
  2906.         dw     offset launch_next    ;Call to load and run program.
  2907.         dw     offset getcom_next    ;Call to find shell name.
  2908.  
  2909. intcommand    proc    near
  2910.         assume    cs:code,ds:code,es:code,ss:code
  2911.         push    bx
  2912.         call    intcmd_1
  2913. intcmd_1:
  2914.         pop    bx            ;Get pointer to sub calls.
  2915.         mov    di,si            ;Copy ptr to command
  2916.         dec    di            ;Back up to cmd line size.
  2917.         push    ds
  2918.         call    intcmd_getcom        ;Get comspec string.
  2919.         call    cs:intcmd_launch    ;Run program.
  2920.         pop    ds
  2921.         pop    bx
  2922.         ret
  2923. intcommand    endp
  2924. intcmd_end    =    $
  2925.  
  2926. ;-----------------------------------------------------------------------------
  2927. ; GETCOMSPEC  Gets the name of the shell program running
  2928. ; Exit:   DS:SI - pointer to the ASCIIZ name of the shell porgram.
  2929. ;-----------------------------------------------------------------------------
  2930. getcom_srchenv    equ    [bx-6]
  2931. getcom_off    dw    0             ;Pointer to offset in COM file
  2932. getcom_size    dw    offset getcom_end - offset getcom_start
  2933. getcom_next    dw    0             ;Ptr to next routine to append
  2934. getcom_lnks    dw    2
  2935. getcom_start    =    $
  2936.         dw    offset searchenv_next     ;Call to search environment blk
  2937.  
  2938. getcomspec    proc    near
  2939.         assume    cs:code,ds:code,es:code,ss:code
  2940.         push    bx
  2941.         call    getcom_1
  2942. getcom_str    db    "COMSPEC"
  2943. getcom_1:
  2944.         pop    bx
  2945.         mov    dx,offset getcom_1 - offset getcom_str
  2946.         mov    si,bx
  2947.         call    getcom_srchenv        ;Get pointer to comspec string
  2948.         pop    bx
  2949.         ret
  2950. getcomspec    endp
  2951. getcom_end    =    $
  2952.  
  2953. ;----------------------------------------------------------------------------
  2954. ;LAUNCH PROG  Routine used to load and run programs.
  2955. ; Entry   DS:SI - pointer to the program name to run.
  2956. ;      ES:DI - pointer to the command line tail.
  2957. ; Exit      return code variable set.
  2958. ;----------------------------------------------------------------------------
  2959. launch_fcb    equ    [bx]
  2960. launch_ptr    dw    0            ;Pointer to offset in COM file
  2961. launch_size    dw    offset launch_end - offset launch_start
  2962. launch_next    dw    0            ;Ptr to next routine to append
  2963. launch_lnks    dw    0            ;Bytes in the dependancy header ;Number of routines called
  2964. launch_start    =    $
  2965.  
  2966. launch_code    proc    near
  2967.         assume    cs:code,ss:code
  2968.         push    bx
  2969.         call    launch_1        ;Push IP on stack
  2970.         db    0            ;Dummy FCB for program
  2971.         db    "DUMMY   FCB"
  2972.         db    0,0,0,0
  2973. launch_1:
  2974.         pop    bx            ;Get pointer to local vars.
  2975.  
  2976.         push    ds
  2977.         push    es            ;Save stack ptr since it is not
  2978.         mov    com_stack_ptr,sp    ;  saved under DOS 2.x.
  2979.  
  2980.         push    cs            ;Create Parameter block on
  2981.         lea    dx,launch_fcb        ;  the stack. Start with 2nd
  2982.         push    dx            ;  FCB.
  2983.         push    cs            ;Push ptr to 1st FCB
  2984.         push    dx
  2985.         push    cs            ;Push ptr to command line tail.
  2986.         push    di
  2987.         xor    ax,ax            ;Use parent env block.
  2988.         push    ax
  2989.         mov    bx,sp            ;Copy pointer to parameter blk
  2990.  
  2991.         mov    ax,4b00h        ;DOS EXEC program.
  2992.         mov    dx,si            ;Get pointer to filename
  2993.         int    21h
  2994.         mov    bp,offset data_start_ptr - offset init_code + 100h
  2995.         mov    bp,cs:[bp]
  2996.         mov    bx,cs            ;Reload BP to access local data
  2997.         cli
  2998.         mov    ss,bx            ;Restore stack
  2999.         mov    sp,com_stack_ptr
  3000.         sti
  3001.         cld                ;Restore default direction
  3002.         pop    es
  3003.         pop    ds
  3004. ;Get return code
  3005.         mov    ah,4dh            ;Get return code
  3006.         int    21h
  3007.         mov    process_rc,al        ;Save
  3008.         pop    bx
  3009.         ret
  3010. launch_code    endp
  3011. launch_end    =       $
  3012.  
  3013. ;----------------------------------------------------------------------------
  3014. ;GOTO  Routine to jump to a label pointed to by a cmd line parameter or
  3015. ;      environment variable.
  3016. ; Entry   DS:SI - pointer to label to find.
  3017. ;            DI - Wait flag/ptr. If <> 0, put goto address at pointer.
  3018. ; Exit      This routine does not return unless the label is not found.
  3019. ;----------------------------------------------------------------------------
  3020. goto_echomsg    equ    [bx-7]
  3021. goto_lblsrch    equ    [bx-5]
  3022. goto_ptr    dw    0            ;Pointer to offset in COM file
  3023. goto_size    dw    offset goto_end - offset goto_start
  3024. goto_next    dw    0            ;Ptr to next routine to append
  3025. goto_lnks    dw    4            ;Bytes in the dependancy header ;Number of routines called
  3026. goto_start    =    $
  3027.         dw    echo_msg_next        ;Used to print error msg
  3028.         dw    lblsrch_next        ;Used to find label
  3029.  
  3030. goto_code    proc    near
  3031.         assume    cs:code,ds:code
  3032.         call    goto_1
  3033.         db    8 dup (" ")
  3034.         db    " Label not found",13,10,0
  3035. goto_1:
  3036.         pop    bx
  3037.         push    di            ;Save wait flag/pointer
  3038.         mov    di,bx            ;Load label into error msg
  3039.         xor    dx,dx            ;Get size of label as it is
  3040.         mov    cx,8            ;  copied into error msg.
  3041. goto_2:
  3042.         lodsb
  3043.         cmp    al," "
  3044.         jbe    goto_4
  3045.         cmp    al,'a'
  3046.         jb    goto_3
  3047.         and    al,0dfh         ;Capitalize label
  3048.         cmp    al,'Z'
  3049.         ja    goto_4
  3050. goto_3:
  3051.         stosb
  3052.         inc    dx
  3053.         loop    goto_2
  3054. goto_4:
  3055.         mov    cx,dx            ;Get size of label
  3056.         mov    si,bx            ;Get pointer to label
  3057.         mov    di,com_label_start    ;Get ptr to start of label list
  3058.         add    di,bp            ;Add offset of data
  3059.         push    bx            ;Save ptr to msg
  3060.         call    goto_lblsrch        ;Call search routine
  3061.         pop    dx            ;Restore ptr to message
  3062.         pop    si            ;Restore Wait flag/pointer
  3063.         jc    goto_5            ;CF set, label not found.
  3064.         mov    ax,[bx+2]        ;Get destination ptr
  3065.         or    si,si            ;See if delay flag <> 0
  3066.         je    goto_41            ;If 0, no delay
  3067.         mov    [bp+si],ax        ;Save ret addr at pointer
  3068.         ret
  3069. goto_41:
  3070.         pop    ax            ;Remove return address
  3071.         push    [bx+2]            ;Push new return address
  3072. goto_exit:
  3073.         ret
  3074. goto_5:
  3075.         mov    bx,dx            ;Set addressability to call
  3076.         call    goto_echomsg        ;Print error message.
  3077.         ret
  3078. goto_code    endp
  3079. goto_end         =    $
  3080.  
  3081. ;----------------------------------------------------------------------------
  3082. ;GOTO DLY  Routine used if goto statment is inside a FOR loop.  Since a for
  3083. ;      loop cannot be exited before it ends, this routine checks to see if
  3084. ;      the GOTO statment was ever executed. If so, we now can jump.
  3085. ; Entry   DS:SI - pointer to destination pointer. 0 = no jump.
  3086. ; Exit      This routine does not return unless the ptr = 0
  3087. ;----------------------------------------------------------------------------
  3088. gotodly_ptr    dw    0            ;Pointer to offset in COM file
  3089. gotodly_size    dw    offset gotodly_end - offset gotodly_start
  3090. gotodly_next    dw    0            ;Ptr to next routine to append
  3091. gotodly_lnks    dw    0            ;Bytes in the dependancy header ;Number of routines called
  3092. gotodly_start    =    $
  3093.  
  3094. gotodly_code    proc    near
  3095.         assume    cs:code,ds:code
  3096.         xor    ax,ax            ;Get pointer, test if zero.
  3097.         or    ax,[si]            ;If zero, return.  If not
  3098.         je    gotodly_exit        ;  push the new destination
  3099.         pop    bx            ;  on the stack and return.
  3100.         push    ax
  3101. gotodly_exit:
  3102.         ret
  3103. gotodly_code    endp
  3104. gotodly_end     =         $
  3105.  
  3106. ;----------------------------------------------------------------------------
  3107. ;LABEL SEARCH Routine to search list of labels to determine goto destination.
  3108. ; Entry   ES:DI - pointer to the first entry in the list. (Assume ES = DS)
  3109. ;      DS:SI - pointer to label to find.
  3110. ;         CX - Length of label
  3111. ; Exit         BX - pointer to matching list entry, or last entry if not found.
  3112. ;         CF - Set if label not found.
  3113. ;----------------------------------------------------------------------------
  3114. lblsrch_ptr    dw    0            ;Pointer to offset in COM file
  3115. lblsrch_size    dw    offset lblsrch_end - offset lblsrch_start
  3116. lblsrch_next    dw    0            ;Ptr to next routine to append
  3117. lblsrch_lnks    dw    0            ;Bytes in the dependancy header ;Number of routines called
  3118. lblsrch_start    =    $
  3119.  
  3120. lblsrch_code    proc    near
  3121.         assume    cs:code,ds:code
  3122.         push    si
  3123.         mov    dx,si            ;Save ptr to label
  3124.         mov    ax,cx            ;Save label length
  3125.         mov    bx,di            ;Get ptr to list
  3126. lblsrch_1:
  3127.         mov    di,bx
  3128.         add    di,4            ;Move to label string
  3129.         mov    si,dx            ;Get ptr to new label
  3130.         mov    cx,ax            ;Get length of label
  3131.         cmp    [di],cl         ;Compare lengths of the labels
  3132.         jne    lblsrch_2
  3133.         inc    di            ;Skip past length byte
  3134.         repe    cmpsb            ;Compare labels.
  3135.         je    lblsrch_4
  3136. lblsrch_2:
  3137.         cmp    word ptr [bx],-1    ;See if at end of list
  3138.         je    lblsrch_3
  3139.         add    bx,[bx]         ;Point to next label
  3140.         jmp    short lblsrch_1
  3141. lblsrch_3:
  3142.         stc                ;No label found.
  3143.         jmp    short lblsrch_exit
  3144. lblsrch_4:
  3145.         clc                ;Label found
  3146. lblsrch_exit:
  3147.         pop    si
  3148.         ret
  3149. lblsrch_code    endp
  3150. lblsrch_end    =    $
  3151.  
  3152. ;-----------------------------------------------------------------------------
  3153. ; IFEQUAL  Compares two strings.
  3154. ; Entry:  DS:SI - Pointer to first ASCIIZ String
  3155. ;      ES:DI - Pointer to second ASCIIZ String
  3156. ;         CX - Length of strings.
  3157. ; Exit:      CF - Clear if equal
  3158. ;-----------------------------------------------------------------------------
  3159. ifequal_off    dw     0            ;Pointer to offset in COM file
  3160. ifequal_size    dw     offset ifequal_end - offset ifequal_start
  3161. ifequal_next    dw     0            ;Ptr to next routine to append
  3162. ifequal_lnks    dw     0
  3163. ifequal_start    =      $
  3164.  
  3165. ifequal     proc    near
  3166.         assume    cs:code,ds:code,es:code,ss:code
  3167.         xor    cx,cx
  3168.         mov    cl,[si-1]        ;Get size of string
  3169.         cmp    cl,[di-1]        ;Compare sizes of strings
  3170.         jne    ifequal_notequal
  3171.         rep    cmpsb            ;Compare strings
  3172.         jne    ifequal_notequal
  3173.         clc
  3174.         ret
  3175. ifequal_notequal:
  3176.         stc
  3177.         ret
  3178. ifequal     endp
  3179. ifequal_end    =    $
  3180.  
  3181. ;-----------------------------------------------------------------------------
  3182. ; IFEXIST  Determines if a file exists.
  3183. ; Entry:  DS:SI - Pointer to ASCIIZ filename.
  3184. ;         DI - Pointer to buffer for disk transfer area.
  3185. ; Exit:      CF - Clear if file exists
  3186. ;         DI - IF file exists, points to filename.
  3187. ;-----------------------------------------------------------------------------
  3188. ifexist_off    dw     0            ;Pointer to offset in COM file
  3189. ifexist_size    dw     offset ifexist_end - offset ifexist_start
  3190. ifexist_next    dw     0            ;Ptr to next routine to append
  3191. ifexist_lnks    dw     0
  3192. ifexist_start    =      $
  3193.  
  3194. ifexist     proc    near
  3195.         assume    cs:code,ds:code,es:code,ss:code
  3196.         mov    dx,di
  3197.         mov    ah,1ah            ;Set DTA
  3198.         int    21h
  3199.  
  3200.         mov    dx,si            ;Copy pointer to filename
  3201.         xor    cx,cx            ;Normal attributes
  3202.         mov    ah,4eh            ;DOS Find First
  3203.         int    21h
  3204.         jc    ifexist_exit
  3205.         add    di,1eh            ;Point DI to filename in DTA
  3206.         clc
  3207. ifexist_exit:
  3208.         ret
  3209. ifexist     endp
  3210. ifexist_end    =    $
  3211.  
  3212. ;-----------------------------------------------------------------------------
  3213. ; IFERRLEV  Compares the value passed with the return code of the last
  3214. ;        program executed.
  3215. ; Entry:     SI - Pointer to ASCIIZ Error level.
  3216. ; Exit:      CF - Clear if process error level above or equal to SI
  3217. ;-----------------------------------------------------------------------------
  3218. iferrlev_off    dw     0            ;Pointer to offset in COM file
  3219. iferrlev_size    dw     offset iferrlev_end - offset iferrlev_start
  3220. iferrlev_next    dw     0            ;Ptr to next routine to append
  3221. iferrlev_lnks    dw     0
  3222. iferrlev_start    =      $
  3223.  
  3224. iferrlev    proc    near
  3225.         assume    cs:code,ds:code,es:code,ss:code
  3226.         xor    ax,ax            ;Convert ASCIIZ number into
  3227.         mov    bx,ax            ;  decimal
  3228. iferrlev_1:
  3229.         mov    bl,[si]         ;Convert error level number
  3230.         sub    bl,'0'                  ;  from ASCII to decimal.
  3231.         jb    iferrlev_2
  3232.         cmp    bl,9
  3233.         ja    iferrlev_2
  3234.         mov    dx,10
  3235.         mul    dx
  3236.         jc    iferrlev_2
  3237.         add    ax,bx            ;Add in digit
  3238.         inc    si
  3239.         jmp    short iferrlev_1
  3240. iferrlev_2:
  3241.         cmp    process_rc,al        ;Compare to last program
  3242.         ret
  3243. iferrlev    endp
  3244. iferrlev_end    =    $
  3245.  
  3246. ;-----------------------------------------------------------------------------
  3247. ; FORLOOP  Processes commands in a FOR loop.
  3248. ; Entry:     SI - Pointer to ASCIIZ set of parameters.
  3249. ;         DI - Pointer loop structure in data area
  3250. ;          LoopCnt    db     0    Member of the set to use
  3251. ;          FirstFlag    db     0    Indicates Find first/next
  3252. ; Exit:      CF - Set if FOR loop complete.
  3253. ;-----------------------------------------------------------------------------
  3254. forloop_getmem    equ    [bx-6]
  3255. forloop_off    dw    0            ;Pointer to offset in COM file
  3256. forloop_size    dw    offset forloop_end - offset forloop_start
  3257. forloop_next    dw    0            ;Ptr to next routine to append
  3258. forloop_lnks    dw    2
  3259. forloop_start    =    $
  3260.         dw    getmember_next
  3261.  
  3262. forloop     proc    near
  3263.         assume    cs:code,ds:code,es:code,ss:code
  3264.         push    bx
  3265.         call    forloop_0
  3266.         db    43 dup (0)        ;Used for DTA
  3267. forloop_0:
  3268.         pop    bx
  3269. ;
  3270. ;Set DTA. If 2nd time or later time looping on a member, use find next to
  3271. ;determine the string for this time through the loop.
  3272. ;
  3273.         lea    dx,[bx]
  3274.         mov    ah,1ah            ;Set DTA
  3275.         int    21h
  3276.  
  3277.         cmp    byte ptr [di+1],0    ;See if first time for member
  3278.         je    forloop_1
  3279.         mov    ah,4fh            ;Find next file
  3280.         int    21h
  3281.         jc    forloop_1        ;Not found, go to next member
  3282.         lea    dx,[bx+1eh]        ;Point to filename in DTA
  3283.         jmp    short forloop_notdone    ;Execute loop body
  3284. ;
  3285. ;First time with this member of the set, if wildcards are in the member,
  3286. ;use DOS find first to get the loop string.
  3287. ;
  3288. forloop_1:
  3289.         mov    byte ptr [di+1],0    ;Clear first/next flag
  3290.         inc    byte ptr [di]        ;Look at next member of the set
  3291.         mov    dh,[di]         ;Get loop count
  3292.         call    forloop_getmem        ;Get member of set.  If no
  3293.         jc    forloop_done        ;  more members, loop done.
  3294.         mov    dx,si            ;Save pointer to member
  3295.         xor    ah,ah            ;Clear wildcard flag
  3296. forloop_2:
  3297.         lodsb                ;Scan set member to check for
  3298.         cmp    al,' '                  ;  any wildcard chars.
  3299.         jbe    forloop_4
  3300.         cmp    al,'?'
  3301.         jne    forloop_3
  3302.         inc    ah            ;Set wildcard found flag
  3303. forloop_3:
  3304.         cmp    al,'*'
  3305.         jne    forloop_2
  3306.         inc    ah            ;Set wildcard found flag
  3307.         jmp    short forloop_2
  3308. forloop_4:
  3309.         mov    byte ptr [si-1],0    ;Set zero terminator.
  3310.         or    ah,ah            ;If no wildcards, execute
  3311.         je    forloop_notdone     ;Execute loop body
  3312.         mov    byte ptr [di+1],1    ;Set first/next flag
  3313.         xor    cx,cx            ;Normal attributes
  3314.         mov    ah,4eh            ;DOS find first
  3315.         int    21h
  3316.         jc    forloop_1        ;If not found, get next member
  3317.         lea    dx,[bx+1eh]        ;Set ptr to filename in DTA
  3318. forloop_notdone:
  3319.         mov    forloop_ptr,dx        ;Set loop data ptr
  3320.         clc
  3321. forloop_exit:
  3322.         pop    bx
  3323.         ret
  3324. forloop_done:
  3325.         mov    word ptr [di],0     ;Clear loop variables
  3326.         stc
  3327.         jmp    short forloop_exit
  3328. forloop     endp
  3329. forloop_end    =    $
  3330.  
  3331. ;-----------------------------------------------------------------------------
  3332. ; FINDENV  Finds the master environment block.
  3333. ; Exit:    Variable Environment_seg set with segment of master environment.
  3334. ;-----------------------------------------------------------------------------
  3335. findenv_dosver    equ    [bx+7]
  3336. findenv_cmdname equ    [bx]
  3337. findenv_off    dw    0             ;Pointer to offset in COM file
  3338. findenv_size    dw    offset findenv_end - offset findenv_start
  3339. findenv_next    dw    0             ;Ptr to next routine to append
  3340. findenv_lnks    dw    0
  3341. findenv_start    =    $
  3342.  
  3343. findenv     proc    near
  3344.         assume    cs:code,ds:code,es:code,ss:code
  3345.         push    bx
  3346.         call    findenv_0
  3347.  
  3348.         db    "COMMAND"
  3349.         dw    0
  3350. findenv_0:
  3351.         pop    bx
  3352.         push    es
  3353.  
  3354.         mov    ax,ds:[2ch]        ;Get default env
  3355.         cmp    environment_seg,ax    ;Check to see if already
  3356.         jne    findenv_jmp_exit    ;  found.
  3357.  
  3358.         push    bx            ;Ver changes BX
  3359.         mov    ah,30h            ;Get dos Version
  3360.         int    21h
  3361.         xchg    al,ah
  3362.         mov    findenv_dosver,ax
  3363.  
  3364.         mov    ah,52h            ;get address of first MCB
  3365.         int    21h
  3366.         mov    ax,es:[bx-2]        ;point ES to MCB
  3367.         mov    cx,20            ;Allow only 20 loops.
  3368.         pop    bx
  3369. findenv_1:
  3370.         mov    es,ax
  3371.         cmp    byte ptr es:[0],"M"     ;check for mcb signature
  3372.         jne    short findenv_exit
  3373.         inc    ax            ;point AX to memory block
  3374.         cmp    ax,es:[1]        ;See if this is a PSP block
  3375.         je    findenv_4
  3376. findenv_2:
  3377.         add    ax,es:[3]        ;Get size of memory block
  3378.         loop    findenv_1
  3379. findenv_jmp_exit:
  3380.         jmp    short findenv_exit
  3381. findenv_4:
  3382.         cmp    word ptr findenv_dosver,0a00h ;If OS/2, use DOS 3.3 method.
  3383.         jae    findenv_5
  3384.         cmp    word ptr findenv_dosver,0400h;If DOS 4.00 or greater,
  3385.         jb    findenv_5          ;  COMMAND.COM may not be the
  3386.         push    ds              ;  first program loaded.  Look
  3387.         lea    si,findenv_cmdname      ;  at the name of the program
  3388.         mov    di,8              ;  stored in the last 8 bytes
  3389.         mov    cx,7              ;  of the memory control
  3390.         repe    cmpsb              ;  block.  If the string
  3391.         pop    ds              ;  "COMMAND" isn't found,
  3392.         jne    findenv_2          ;  keep looking.
  3393. findenv_5:
  3394.         mov    dx,ax            ;Save PSP seg of command.com
  3395.         mov    es,ax
  3396.         mov    bx,es:[2ch]        ;Get seg of prog environment
  3397.         mov    ax,bx
  3398.         dec    bx
  3399.         mov    es,bx
  3400.         cmp    byte ptr es:[0],"M"     ;See if valid memory block
  3401.         je    findenv_found
  3402.         mov    ax,dx            ;Get back cmd.com segment
  3403.         dec    ax            ;Point back to mcb
  3404.         mov    es,ax
  3405. findenv_6:
  3406.         add    ax,es:[3]        ;If master env segment not 
  3407.         inc    ax            ;  saved at 2Ch of the PSP, 
  3408.         mov    es,ax            ;  scan the memory blocks
  3409.         cmp    es:[1],dx        ;  for first segment
  3410.         je    findenv_7        ;  owned by command.com.
  3411.         loop    findenv_6
  3412.         jmp    short findenv_exit    ;Master env not found.
  3413. findenv_7:    
  3414.         inc    ax            ;Point AX to env segment
  3415. findenv_found:
  3416.         mov    environment_seg,ax    ;Save pointer to master env 
  3417. findenv_exit:
  3418.         pop    es
  3419.         pop    bx
  3420.         ret
  3421. findenv     endp
  3422. findenv_end    =    $
  3423.  
  3424. ;-----------------------------------------------------------------------------
  3425. ; SET_ENV  Sets/resets environment variables.
  3426. ; Entry:  DS:SI - pointer to ASCII string containing the environment variable
  3427. ;          and, optionally, the string to assign.
  3428. ;            DI - Flag to indicate setting of PATH and PROMPT vars
  3429. ;                 0 = Normal Env var, 1 = PROMPT var, 2 = PATH var.
  3430. ;-----------------------------------------------------------------------------
  3431. setenv_findenv    equ    [bx-10]
  3432. setenv_echo    equ    [bx-8]
  3433. setenv_serchenv equ    [bx-6]
  3434. setenv_pathflag    equ    [bx]
  3435. setenv_fullmsg    equ    [bx+1]
  3436. setenv_off    dw    0            ;Pointer to offset in COM file
  3437. setenv_size    dw    offset setenv_end - offset setenv_start
  3438. setenv_next    dw    0            ;Ptr to next routine to append
  3439. setenv_lnks    dw    6
  3440. setenv_start    =    $
  3441.         dw    offset findenv_next    ;Call to find the master env
  3442.         dw    offset echo_msg_next    ;Call to print line.
  3443.         dw    offset searchenv_next    ;Call to search environment blk
  3444.  
  3445. set_env     proc near
  3446.         assume    ds:nothing,es:nothing
  3447.         push    bx
  3448.         call    setenv_1
  3449.         db    0            ;PATH/PROMPT flag storage
  3450.         db    "Out of environment space",13,10,0
  3451. setenv_1:
  3452.         pop    bx            ;Set up local addressing
  3453.         mov    ax,di
  3454.         xchg    al,ah
  3455.         mov    setenv_pathflag,ah
  3456.         push    ax
  3457.         call    setenv_findenv        ;Find master env block
  3458.         pop    ax
  3459.         push    bp
  3460.         push    es
  3461.         mov    cx,255
  3462.         xor    dx,dx
  3463.         push    si            ;Save ptr to new env var
  3464.         mov    di,si
  3465. setenv_2:
  3466.         lodsb
  3467.         or     ah,ah            ;See if PATH or PROMPT
  3468.         je    setenv_23
  3469.         cmp    al," "            ;If PATH or PROMPT statments,
  3470.         jne    setenv_23        ;  remove any spaces between    
  3471.         mov    al,"="            ;  variable and assignment.
  3472.         push    di
  3473.         stosb
  3474. setenv_20:
  3475.         lodsb                ;Scan past equal sign 
  3476.         cmp    al," "            
  3477.         je    setenv_20
  3478.         cmp    al,"="
  3479.         je    setenv_20
  3480. setenv_21:
  3481.         stosb    
  3482.         or    al,al
  3483.         je    setenv_22
  3484.         lodsb                ;Remove spaces in set string.
  3485.         jmp    short setenv_21
  3486. setenv_22:
  3487.         pop    di
  3488.         jmp    short setenv_4
  3489. setenv_23:
  3490.         cmp    al,"="                  ;Scan until end of variable
  3491.         je    setenv_4        ;  found.
  3492.         cmp    al,'a'
  3493.         jb    setenv_3
  3494.         cmp    al,'z'
  3495.         ja    setenv_3
  3496.         and    al,0dfh         ;Capitalize variable
  3497. setenv_3:
  3498.         stosb
  3499.         inc    dx
  3500.         loop    setenv_2
  3501. setenv_4:
  3502.         pop    si
  3503.         mov    ax,si
  3504.         inc    di
  3505.         cmp    byte ptr cs:[di]," "    ;If nothing past '=' then
  3506.         jae    setenv_41        ;  simply erase var from env.
  3507.         xor    ax,ax
  3508. setenv_41:
  3509.         push    ax
  3510.         call    setenv_serchenv     ;Get pointer to variable
  3511.         pop    dx            ;Save ptr to var
  3512.         push    ds
  3513.         pop    es
  3514.         mov    di,si            ;Copy pointer to variable
  3515.         jc    setenv_61
  3516.  
  3517.         xor    al,al            ;Scan backwards to find start
  3518.         std                ;  of var name
  3519.         mov    cx,256
  3520.         repne    scasb
  3521.         inc    di
  3522.         inc    di
  3523.         push    di
  3524.         cld                ;Scan forward to find end of
  3525.         mov    cx,256            ;  variable.
  3526.         repne    scasb
  3527.         mov    si,di
  3528.         pop    di
  3529.         xor    ah,ah
  3530. setenv_5:
  3531.         lodsb                ;Move byte from past var to
  3532.         stosb                ;  cover up current assignment
  3533.         or    ah,al            ;If two zeros in a row then
  3534.         je    setenv_6        ;  end of env vars.
  3535.         mov    ah,al
  3536.         jmp    short setenv_5
  3537. setenv_6:
  3538.         dec    di            ;Back up before last zero
  3539. setenv_61:
  3540.         push    cs
  3541.         pop    ds
  3542.         mov    si,dx            ;Get back ptr to env var
  3543.         or    si,si            ;See if var assignment
  3544.         je    setenv_9
  3545.  
  3546.         push    es            ;Get size of the environment
  3547.         mov    ax,es            ;  block by reading the size
  3548.         dec    ax            ;  in the memory control block.
  3549.         mov    es,ax
  3550.         mov    bp,es:[3]
  3551.         mov    cl,4
  3552.         shl    bp,cl            ;Convert to bytes.
  3553.         dec    bp
  3554.         dec    bp
  3555.         pop    es
  3556.         mov    ah,setenv_pathflag    ;Get pathflag byte
  3557. setenv_7:
  3558.         lodsb                ;Copy new env var
  3559.         cmp    ah,2    
  3560.         jne    setenv_71        ;If PATH var, make upper case.
  3561.         cmp    al,'a'
  3562.         jb     setenv_71
  3563.         cmp    al,'z'
  3564.         ja    setenv_71
  3565.         and    al,0dfh            
  3566. setenv_71:    
  3567.         stosb
  3568.         or    al,al            ;Check for end of variable.
  3569.         je    setenv_8
  3570.         cmp    di,bp            ;Check for end of env block.
  3571.         jb    setenv_7
  3572.         push    cs
  3573.         pop    ds
  3574.         lea    si,setenv_fullmsg    ;If environment block full,
  3575.         call    setenv_echo        ;  print message.
  3576.         xor    al,al            ;Terminate with zeros.
  3577.         stosb
  3578. setenv_8:
  3579.         xor    al,al
  3580.         stosb
  3581. setenv_9:
  3582.         pop    es
  3583.         pop    bp
  3584.         pop    bx
  3585.         ret
  3586. set_env     endp
  3587. setenv_end    =    $
  3588.  
  3589. ;-----------------------------------------------------------------------------
  3590. ; REDIROO  Opens a file for output redirection.
  3591. ; Entry:  DS:SI - pointer to ASCII filename to open.
  3592. ;         DI - 0  open new file, 1 append to existing file.
  3593. ;-----------------------------------------------------------------------------
  3594. rediroo_off    dw    0            ;Pointer to offset in COM file
  3595. rediroo_size    dw    offset rediroo_end - offset rediroo_start
  3596. rediroo_next    dw    0            ;Ptr to next routine to append
  3597. rediroo_lnks    dw    0
  3598. rediroo_start    =    $
  3599.  
  3600. rediroo     proc near
  3601.         assume    ds:nothing,es:nothing
  3602.  
  3603.         mov    word ptr stdout_hdl,-1    ;Clear handle
  3604.         mov    dx,si            ;Get ptr to outfile file
  3605.         xor    cx,cx            ;Normal attributes
  3606.         mov    ax,3c02h        ;Create file
  3607.         or    di,di            ;See if append or new file
  3608.         je    rediroo_2
  3609.         inc    ah            ;Open file
  3610. rediroo_2:
  3611.         int    21h
  3612.         jc    rediroo_exit
  3613.         mov    bx,ax            ;Copy file handle
  3614.         or    di,di
  3615.         je    rediroo_3
  3616.         mov    ax,4202h        ;Move file ptr to end of file
  3617.         xor    dx,dx
  3618.         mov    cx,dx
  3619.         int    21h
  3620.         jc    rediroo_exit
  3621. rediroo_3:
  3622.         mov    outfile_hdl,bx        ;Save output file handle
  3623.         push    bx
  3624.         mov    ah,45h            ;Duplicate output handle
  3625.         mov    bx,1            ;Std output handle
  3626.         int    21h
  3627.         mov    stdout_hdl,ax        ;Save dup std output handle
  3628.  
  3629.         mov    cx,1
  3630.         pop    bx
  3631.         mov    ah,46h            ;Force dup file handle
  3632.         int    21h
  3633. rediroo_exit:
  3634.         ret
  3635. rediroo     endp
  3636. rediroo_end    =    $
  3637.  
  3638. ;-----------------------------------------------------------------------------
  3639. ; REDIRCO  Closes a file used for output redirection.
  3640. ;-----------------------------------------------------------------------------
  3641. redirco_off    dw    0            ;Pointer to offset in COM file
  3642. redirco_size    dw    offset redirco_end - offset redirco_start
  3643. redirco_next    dw    0            ;Ptr to next routine to append
  3644. redirco_lnks    dw    0
  3645. redirco_start    =    $
  3646.  
  3647. redirco     proc near
  3648.         assume    ds:nothing,es:nothing
  3649.         cmp    word ptr stdout_hdl,-1    ;If error on redirect, skip
  3650.         je    redirco_exit        ;  restore.
  3651.  
  3652.         mov    ah,46h            ;Force restore of std out
  3653.         mov    bx,stdout_hdl
  3654.         mov    cx,1
  3655.         int    21h
  3656.  
  3657.         mov    ah,3eh            ;Close file
  3658.         mov    bx,outfile_hdl        ;Get output file handle
  3659.         int    21h
  3660. redirco_exit:
  3661.         ret
  3662. redirco     endp
  3663. redirco_end    =    $
  3664.  
  3665. ;-----------------------------------------------------------------------------
  3666. ; REDIROI  Opens a file for input redirection.
  3667. ; Entry:  DS:SI - pointer to ASCII filename to open.
  3668. ;         DI - 0  open new file, 1 append to existing file.
  3669. ;-----------------------------------------------------------------------------
  3670. rediroi_off    dw    0            ;Pointer to offset in COM file
  3671. rediroi_size    dw    offset rediroi_end - offset rediroi_start
  3672. rediroi_next    dw    0            ;Ptr to next routine to append
  3673. rediroi_lnks    dw    0
  3674. rediroi_start    =    $
  3675.  
  3676. rediroi     proc near
  3677.         assume    ds:nothing,es:nothing
  3678.  
  3679.         mov    word ptr stdin_hdl,-1    ;Clear handle
  3680.         mov    dx,si            ;Get ptr to outfile file
  3681.         mov    ax,3d00h        ;Open file, Read only
  3682.         int    21h
  3683.         jc    rediroi_exit
  3684.         mov    infile_hdl,ax        ;Save input file handle
  3685.         push    ax
  3686.  
  3687.         mov    ah,45h            ;Duplicate input handle
  3688.         xor    bx,bx
  3689.         int    21h
  3690.         mov    stdin_hdl,ax        ;Save dup std input handle
  3691.  
  3692.         xor    cx,cx
  3693.         pop    bx
  3694.         mov    ah,46h            ;Force dup file handle
  3695.         int    21h
  3696. rediroi_exit:
  3697.         ret
  3698. rediroi     endp
  3699. rediroi_end    =    $
  3700.  
  3701. ;-----------------------------------------------------------------------------
  3702. ; REDIRCI  Closes a file used for input redirection.
  3703. ;-----------------------------------------------------------------------------
  3704. redirci_off    dw    0            ;Pointer to offset in COM file
  3705. redirci_size    dw    offset redirci_end - offset redirci_start
  3706. redirci_next    dw    0            ;Ptr to next routine to append
  3707. redirci_lnks    dw    0
  3708. redirci_start    =    $
  3709.  
  3710. redirci     proc near
  3711.         assume    ds:nothing,es:nothing
  3712.         cmp    word ptr stdin_hdl,-1    ;If error on redirect, skip
  3713.         je    redirci_exit        ;  restore.
  3714.  
  3715.         mov    ah,46h            ;Force restore of std in hdl
  3716.         xor    cx,cx
  3717.         mov    bx,stdin_hdl
  3718.         int    21h
  3719.  
  3720.         mov    ah,3eh            ;Close file
  3721.         mov    bx,infile_hdl        ;Get input file handle
  3722.         int    21h
  3723. redirci_exit:
  3724.         ret
  3725. redirci     endp
  3726. redirci_end    =    $
  3727.  
  3728. ;-----------------------------------------------------------------------------
  3729. ; REDIRDEL Deletes piping file.
  3730. ; Entry:  DS:SI - pointer to ASCII filename to delete.
  3731. ;-----------------------------------------------------------------------------
  3732. redirdel_off    dw    0            ;Pointer to offset in COM file
  3733. redirdel_size    dw    offset redirdel_end - offset redirdel_start
  3734. redirdel_next    dw    0            ;Ptr to next routine to append
  3735. redirdel_lnks    dw    0
  3736. redirdel_start    =    $
  3737.  
  3738. redirdel     proc near
  3739.         assume    ds:nothing,es:nothing
  3740.  
  3741.         mov    dx,si            ;Copy pointer to filename
  3742.         mov    ah,41h            ;Delete file
  3743.         int    21h
  3744.         ret
  3745. redirdel     endp
  3746. redirdel_end    =    $
  3747.  
  3748. initialize    endp
  3749.         even                ;compiler stack on word boundry
  3750. end_of_code    =    $
  3751. code        ends
  3752.  
  3753. end        main
  3754. ,0dfh            
  3755. setenv_71:    
  3756.         stosb
  3757.         or    al,al            ;Check